簡體   English   中英

多請求動畫幀性能

[英]Multiple requestAnimationFrame performance

如果我正在做多個動畫,添加多個requestAnimationFrame回調是否可以提高性能? 例子:

function anim1() {
    // animate element 1
}

function anim2() {
    // animate element 2
}

function anim3() {
    // animate element 3
}

requestAnimationFrame(anim1);
requestAnimationFrame(anim2);
requestAnimationFrame(anim3);

或者它被證明比使用單個回調更糟糕:

(function anim() {
    requestAnimationFrame(anim);
    anim1();
    anim2();
    anim3();
}());

我問是因為我真的不知道幕后發生了什么,當您多次調用requestAnimationFrame時是否會排隊回調?

我認為這些答案中的任何一個都沒有真正解釋我正在尋找的內容:“對 requestAnimationFrame 進行 n 次調用”得到去抖動(即每幀出列 1 個)或在下一幀中全部被調用。

當 requestAnimationFrame() 排隊的回調開始在單個幀中觸發多個回調 ( mdn )

這表明后者,可以在同一幀中調用多個回調。

我通過以下測試確認。 60 Hz 的刷新率轉換為 17 毫秒的周期。 如果是前者,則沒有 2 個時間戳彼此相差 17 毫秒以內,但事實並非如此。

 let sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); let update = async timestamp => { console.log('update called', timestamp) await sleep(10); requestAnimationFrame(update); } requestAnimationFrame(update); requestAnimationFrame(update); requestAnimationFrame(update); requestAnimationFrame(update); requestAnimationFrame(update); requestAnimationFrame(update); requestAnimationFrame(update); requestAnimationFrame(update); requestAnimationFrame(update); requestAnimationFrame(update); requestAnimationFrame(update); requestAnimationFrame(update); requestAnimationFrame(update); requestAnimationFrame(update); requestAnimationFrame(update);

您應該只使用一個requestAnimationFrame調用作為對requestAnimationFrame調用堆棧。 因此,單個回調版本的性能更高。

有人對此進行了基准測試。 讓我們談談...

https://jsperf.com/single-raf-draw-calls-vs-multiple-raf-draw-calls

我查看了性能比較(你也應該看看)。 歡迎你不同意。 這些是在畫布元素上繪制基元。

        function timeStamp() {
          return window.performance && window.performance.now ? window.performance.now() : new Date().getTime();
        }

        function frame() {
            drawCircle();
            drawLines();
            drawRect();
        }

        function render() {
            if (timeStamp() >= (time || timeStamp())) {
                time = timeStamp() + delayDraw;
                frame();
            } 
            requestAnimationFrame(render);
        }

        function render1() {
            if (timeStamp() >= (time || timeStamp())) {
                time = timeStamp() + delayDraw;
                drawCircle();
            } 
            requestAnimationFrame(render1);
        }

        function render2() {
            if (timeStamp() >= (time || timeStamp())) {
                time = timeStamp() + delayDraw;
                drawRect();
            } 
            requestAnimationFrame(render2);
        }

        function render3() {
            if (timeStamp() >= (time || timeStamp())) {
                time = timeStamp() + delayDraw;
                drawLines();
            } 
            requestAnimationFrame(render3);
        }

我認為這段代碼實際上是對 7 次時間戳()調用和 2 次時間戳()調用進行基准測試。 看看 Chrome 46 和 47 的區別。

  • Chrome 46: 12k /秒(1 次調用)與12k /秒(3 次調用)
  • Chrome 47: 270k /秒(1 次調用)與810k /秒(3 次調用)

我認為這優化得很好,沒有任何區別。 這只是在此時測量噪聲。

我的結論是這不需要針對我的應用程序進行手動優化。

如果您擔心性能,請查看 Chrome 59 (1.8m ops/sec) 與 Chrome 71 (506k ops/sec) 之間的差異。

requestAnimationFrame 綁定一個函數調用並返回 frameID。 請求多個幀與向事件添加多個事件偵聽器不同 - 您的每個函數都在另一個幀中調用。 因此,如果您連續(每個函數遞歸地調用自身)請求幾幀,您就會失去所有更新都在一幀內呈現的好處。 所以即使有高幀率動畫也可能看起來不那么流暢。

但是:您只能對所有方法使用 cancelAnimationFrame(frameID) 並且可能需要一些額外的代碼來取消單個動畫

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM