Canvas的一個性能研究:到底怎麼影響咱們的Canvas性能

今天一個偶然的幾乎,發現一個怪異現象。因而探究了一下,有點意思,與君共勉。html

源於一個需求:我要畫更多的對象

咱們都知道,Canvas的繪製,會受硬件影響。不一樣的硬件設備會有明顯的性能上的差別引發卡頓。可是如何影響的呢?canvas

下面的實驗代碼

<!DOCTYPE html>
<html>
  <head>
  </head>

  <body>
    <div id="canvas" style="width: 600px; height: 400px;"></div>
    <script src="ryou-test.js"></script>
    <script src="example.js"></script>
  </body>
</html>
複製代碼
(function(global) {
  const RyouList = global.RyouList = function (dom, opts) {
    this._root = dom;
    this._options = {
      ratio: 1,
      ...opts
    };
    this._init();

    this._shouldUpdate = false;
    this._eles = [];
  }

  RyouList.prototype._init = function () {
    const ret = this._root.getBoundingClientRect();

    const _div = document.createElement("div");
    const _cvs = document.createElement("canvas");

    this._ctx = _cvs.getContext("2d");

    _div.appendChild(_cvs);
    _div.style.width = ret.width + 'px';
    _div.style.height = ret.height + 'px';

    _cvs.width = ret.width * this._options.ratio;
    _cvs.height = ret.height * this._options.ratio;

    this._rect = {
      width: _cvs.width,
      height: _cvs.height
    }

    this._root.appendChild(_div);
  }

  RyouList.prototype.render = function () {
    this._ctx.clearRect(0, 0, this._rect.width, this._rect.height);

    const len = this._eles.length;
    for (let i = 0; i < len; i++) {
      this._ctx.beginPath();
      this._ctx.fillStyle = "#0f0";
      this._ctx.arc(this._eles[i].x, this._eles[i].y, this._eles[i].r, 0, 2 * Math.PI);
      this._ctx.fill();
    }
  }

  RyouList.prototype.add = function () {
    this._shouldUpdate = true;
    let x = Math.random() * this._rect.width;
    let y = Math.random() * this._rect.height;

    this._eles.push({
      type: "cicle",
      x: x,
      y: y,
      r: 5
    })
  }
  
}(window))

const rc = new RyouList(document.getElementById("canvas"));

for (let i = 0; i < 26929; i++) { // ---》 注意這個for循環。
  rc.add();
}
let first = new Date().getTime()
rc.render();
console.log(new Date().getTime() - first)
複製代碼

實驗1

  1. 咱們將上面代碼的for循環調整到20000-26929.沒存渲染頁面打印結果在40ms左右。
  2. 咱們將上面代碼的for循環調整到26930,奇蹟發生麼,445ms左右。
  3. 咱們將上面代碼的for循環調整到32000,打印結果在450-550ms之間
  4. 咱們將上面代碼的for循環調整到42000,打印結果在700ms以上

這是一個頗有意思的事情,由於個人代碼僅僅記錄了for循環建立路徑打印這一過程,所以是不受建立元素,計算隨機位置的影響的,去掉for循環的性能影響,基本上是比較接近Canvas的渲染消耗的。app

實驗2

  1. 咱們將上面代碼的園的半徑調整到2,for循環爲20000-26929,打印結果是19ms左右
  2. 咱們將上面代碼的園的半徑調整到2,for循環爲32000,打印結果是49ms左右
  3. 咱們將上面代碼的園的半徑調整到2,for循環爲42000,打印結果是49ms左右
  4. 咱們將上面代碼的園的半徑調整到2,for循環爲52000,打印結果是400ms左右

是否是頗有意思?Canvas的性能降低並非線性的,而是以指數級的。在達到某個值的時候,這個性能會指數級降低dom

實驗3

  1. 咱們將上面代碼的園的半徑調整到8,for循環爲20000-26929,打印結果是300ms左右
  2. 咱們將上面代碼的園的半徑調整到8,for循環爲32000,打印結果是400+ms左右
  3. 咱們將上面代碼的園的半徑調整到8,for循環爲42000,打印結果是500ms左右
  4. 咱們將上面代碼的園的半徑調整到8,for循環爲52000,打印結果是700ms左右

是否是頗有意思?經過以上測試,Canvas的渲染並非受咱們繪製多少圖形影響。性能

實驗4

  1. 咱們將上面代碼的園的半徑調整到20,for循環爲20000-26929,打印結果是1800ms左右
  2. 咱們將上面代碼的園的半徑調整到20,for循環爲4000,打印結果是40ms左右

再一次證實,Canvas的渲染並非受咱們繪製多少圖形影響的。測試

結論

以上4次實驗,發現,咱們在Canvas繪製多少次對性能的直接影響其實並不大,可是咱們增大每次繪製的圖形的大小的時候,性能會嚴重影響。ui

因此,Canvas性能的直接影響因素應該是咱們繪製的【像素總數】,而不是繪製的元素數量。當咱們繪製的像素總數達到一個閾值,那麼Canvas的性能會指數級降低,這個閾值極可能就是由硬件決定的。this

相關文章
相關標籤/搜索