setTimeout和requestAnimationFrame


在前端做一些持續執行的動畫時,一般會通過setTimeOut去實現,其實js還有另一個API和setTimeout功能類似,就是requestAnimationFrame,在說requestAnimationFrame之前項說說setTimeOut和setInterval

setTimeout 和 setInterval區別

  • setTimeout: 指定延期后調用函數,每次setTimeout計到期到向事件隊列推入一個事件
  • setInterval:以指定周期,向事件隊列推入一個事件

setInterval存在的一些問題:

定時器代碼可能在代碼再次被添加到隊列之前還沒有完成執行,結果導致定時器代碼連續運行好幾次,而之間沒有任何停頓。

而javascript引擎對這個問題的解決是:當使用setInterval()時,僅當沒有該定時器的任何其他代碼實例時,才將定時器代碼添加到隊列中。這確保了定時器代碼加入到隊列中的最小時間間隔為指定間隔。

但是,這樣會導致兩個問題:

  • 1、某些間隔被跳過;
  • 2、多個定時器的代碼執行之間的間隔可能比預期的小

使用setTimeout構造輪詢模擬定時器

在前一個定時器代碼執行完之前,不會向隊列插入新的定時器代碼,確保不會有任何缺失的間隔。而且,它可以保證在下一次定時器代碼執行之前,至少要等待指定的間隔,避免了連續的運行

setTimeout(function fn(){
    console.log('我被調用了');
    setTimeout(fn, 100);
},100);

  

requestAnimationFrame

requestAnimationFrame是瀏覽器用於定時循環操作的一個接口,類似於setTimeout,主要用途是按幀對網頁進行重繪。

顯示器有固定的刷新頻率(60Hz或75Hz),也就是說,每秒最多只能重繪60次或75次,requestAnimationFrame的基本思想就是與這個刷新頻率保持同步,利用這個刷新頻率進行頁面重繪。

此外,使用這個API,一旦頁面不處於瀏覽器的當前標簽,就會自動停止刷新。這就節省了CPU、GPU和電力。

requestAnimationFrame是在主線程上完成。這意味着,如果主線程非常繁忙,requestAnimationFrame的動畫效果會大打折扣。

requestAnimationFrame使用一個回調函數作為參數。這個回調函數會在瀏覽器重繪之前調用

requestID = window.requestAnimationFrame(callback);

 兼容處理

window.requestAnimFrame = (function(){
    return  window.requestAnimationFrame       ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame    ||
            window.oRequestAnimationFrame      ||
            window.msRequestAnimationFrame     ||
            function( callback ){
            window.setTimeout(callback, 1000 / 60);
        };
})();

 

如何使用

function animation(){
       requestAnimFrame(animation);
   }

結束動畫

cancelAnimationFrame(animationId);

requestIdleCallback()

requestIdleCallback會在每次屏幕刷新時,判斷當前幀是否還有多余的時間,如果有,則會調用回調函數

利用這個特性,我們可以在動畫執行的期間,利用每幀的空閑時間來進行數據發送的操作,或者一些優先級比較低的操作,此時不會使影響到動畫的性能,或者和requestAnimationFrame搭配,可以實現一些頁面性能方面的的優化,

react 的 fiber 架構也是基於 requestIdleCallback 實現的

總結

  • 從單線程模型和任務隊列出發理解 setTimeout(fn, 0),並不是立即執行。
  • JS 動畫用requestAnimationFrame 會比 setInterval 效果更好
  • requestIdleCallback()常用來切割長任務,利用空閑時間執行,避免主線程長時間阻塞。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM