requestAnimationFrame詳解及對比

 

目錄

1、什麼是requestAnimationFrame 

2、 設置這個API的目的是什麼? 

3、 requestAnimationFrame的優缺點 

①優點: 

②缺點: 

4、 requestAnimationFrame的使用 

①語法: 

②範例: 

5、setTimeout(補充) 

 

 

1、什麼是requestAnimationFrame

requestAnimationFrame是瀏覽器用於定時循環操作的一個接口,類似於setTimeout,主要用途是按幀對網頁進行重繪,讓各種網頁動畫效果(DOM動畫、Canvas動畫、SVG動畫、WebGL動畫)能夠有一個統一的刷新機制,從而節省系統資源,提高系統性能,改善視覺效果。

在運行過程中,window.requestAnimationFrame() 告訴瀏覽器——你希望執行一個動畫,並且要求瀏覽器在下次重繪之前調用指定的回調函數更新動畫。該方法需要傳入一個回調函數作爲參數,該回調函數會在瀏覽器下一次重繪之前執行

 

注意:若你想在瀏覽器下次重繪之前繼續更新下一幀動畫,那麼回調函數自身必須再次調用window.requestAnimationFrame()

 

2、設置這個API的目的是什麼?

用js來實現動畫,一般是用setTimeout或setInterval這兩個函數。css3動畫出來後,實現動畫的方式又多了一種選擇,而且性能和流暢度也得到了很大的提升。

但是css3動畫還是有不少侷限性,比如不是所有屬性都能參與動畫、動畫緩動效果太少、無法完全控制動畫過程等等。但是setTimeout和setInterval有着嚴重的性能問題,就算現代瀏覽器對其極力優化,但還是無法跟css3的動畫性能相提並論。

 

 

有需求就會有市場,有痛點就會有想要去解決

 

requestAnimationFrame 是一個專門爲實現高性能的幀動畫而設計的API,目前不管是移動端還是桌面端,新版本的瀏覽器都已經支持了這個API。

3、requestAnimationFrame的優缺點

(相對於setTimeout、setInterval)

 

①優點:

  • requestAnimationFrame 會把每一幀中的所有DOM操作集中起來,在一次重繪或迴流中就完成,並且重繪或迴流的時間間隔緊緊跟隨瀏覽器的刷新頻率。充分利用了顯示器的刷新機制,比較節省系統資源(顯示器有固定的刷新頻率(60Hz或75Hz),也就是說,每秒最多隻能重繪60次或75次)。
  • requestAnimationFrame是一個全局函數。調用requestAnimationFrame後,它會要求瀏覽器根據自己的頻率進行一次重繪,它會接收一個回調函數作爲參數,在瀏覽器即將開始重繪時,會調用這個函數,並會給這個函數傳入調用回調函數時的時間作爲參數。之後會反覆不斷地調用requestAnimationFrame,以達到動畫效果;
  • 節省了CPU、GPU和電力。使用setTimeout實現的動畫,當頁面被隱藏或最小化時,setTimeout 仍然在後臺執行動畫任務,此時刷新動畫是沒有意義的,完全是浪費CPU等資源。而requestAnimationFrame則完全不同,當頁面處理未激活的狀態下,該頁面的屏幕刷新任務也會被系統暫停,因此跟着系統步伐走的requestAnimationFrame也會停止渲染,當頁面被激活時,動畫就從上次停留的地方繼續執行,有效節省了CPU、GPU和電力開銷。

 

②缺點:

  • 由於requestAnimationFrame目前還存在兼容性問題,而且不同的瀏覽器還需要帶不同的前綴。因此需要通過降級的方式對requestAnimationFrame進行封裝,根據不同瀏覽器的情況從高級特性往低進行回退。
  • requestAnimationFrame是在主線程上完成。這意味着,如果主線程非常繁忙,requestAnimationFrame的動畫效果會大打折扣。

 

4、requestAnimationFrame的使用

 

①語法:

window.requestAnimationFrame(callback);

 

參數:callback

下一次重繪之前更新動畫幀所調用的函數(即上面所說的回調函數)。該回調函數會被傳入DOMHighResTimeStamp參數,該參數與performance.now()的返回值相同,它表示requestAnimationFrame() 開始去執行回調函數的時刻。

返回值:

一個 long 整數,請求 ID ,是回調列表中唯一的標識。是個非零值,沒別的意義。你可以傳這個值給 window.cancelAnimationFrame() 以取消回調函數。

 

②範例:

var start = null;var element = document.getElementById('SomeElementYouWantToAnimate');

element.style.position = 'absolute';

function step(timestamp) {

  if (!start) start = timestamp;

  var progress = timestamp - start;

  element.style.left = Math.min(progress / 10, 200) + 'px';

  if (progress < 2000) {

    window.requestAnimationFrame(step);

  }}



window.requestAnimationFrame(step);
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

(範例來源於MDN web docs)

 

 

5、setTimeout補充

setTimeout 是通過設置一個間隔時間來不斷的改變圖像的位置,從而達到動畫效果的。但是利用seTimeout實現的動畫在某些低端機上會出現卡頓、抖動的現象。

那爲什麼會出現卡頓呢

  1. setTimeout的執行時間並不是確定的。在Javascript中, setTimeout 任務被放進了異步隊列中,只有當主線程上的任務執行完以後,纔會去檢查該隊列裏的任務是否需要開始執行,因此 setTimeout 的實際執行時間一般要比其設定的時間晚一些。
  2. 刷新頻率受屏幕分辨率屏幕尺寸的影響,因此不同設備的屏幕刷新頻率可能會不同,而 setTimeout只能設置一個固定的時間間隔,這個時間不一定和屏幕的刷新時間相同。

以上兩種情況都會導致setTimeout的執行步調和屏幕的刷新率不一致,從而出現掉幀現象。

 

那爲什麼步調不一致就會引起丟幀呢?

首先要明白,setTimeout的執行只是在內存中對圖像屬性進行改變,這個變化必須要等到屏幕下次刷新時纔會被更新到屏幕上。如果兩者的步調不一致,就可能會導致中間某一幀的操作被跨越過去,而直接更新下一幀的圖像。

 

舉個栗子:

假設屏幕每隔16.7ms刷新一次,而setTimeout每隔10ms設置圖像向左移動1px, 就會出現如下繪製過程:

  • 第0ms: 屏幕未刷新,等待中,setTimeout也未執行,等待中;
  • 第10ms: 屏幕未刷新,等待中,setTimeout開始執行並設置圖像屬性left=1px;
  • 第16.7ms: 屏幕開始刷新,屏幕上的圖像向左移動了1px, setTimeout 未執行,繼續等待中;
  • 第20ms: 屏幕未刷新,等待中,setTimeout開始執行並設置left=2px;
  • 第30ms: 屏幕未刷新,等待中,setTimeout開始執行並設置left=3px;
  • 第33.4ms:屏幕開始刷新,屏幕上的圖像向左移動了3px, setTimeout未執行,繼續等待中;

從上面的繪製過程中可以看出,屏幕沒有更新left=2px的那一幀畫面,圖像直接從1px的位置跳到了3px的的位置,這就是丟幀現象,這種現象就會引起動畫卡頓。

(setTimeout解釋大部分來源於百度,經過作者略微修改,僅供參考)

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章