requestAnimationFrame-制作逐幀動畫

window.requestAnimationFrame() 方法告訴瀏覽器您希望執行動畫,并請求瀏覽器調用指定的函數在下一次重繪之前更新動畫。該方法將在重繪之前調用的回調作為參數。如果你想做逐幀動畫的時候,你應該用這個方法。這就要求你的動畫函數執行會先于瀏覽器重繪動作。通常來說,被調用的頻率是每秒60次,但是一般會遵循W3C標準規定的頻率。如果是后臺標簽頁面,重繪頻率則會大大降低。

瀏覽器的顯示頻率一般是16.7ms,我們將setTimeout的間隔時間設為16.7ms,節奏會如下圖第一行展示 。但如果我們將間隔時間設為10ms,那么節奏會如下圖第二行展示。


frame-lost.png

舉個例子:

國慶北京高速,最多每16.7s通過一輛車,結果,突然插入一批setTimeout的軍車,強行要10s通過。顯然,這是超負荷的,要想順利進行,只能讓第三輛車直接消失(正如顯示繪制第三幀的丟失)。然而,這是不現實的,于是就有了會堵車!

同樣的,顯示器16.7ms刷新間隔之前發生了其他繪制請求(setTimeout),導致所有第三幀丟失,繼而導致動畫斷續顯示(堵車的感覺),這就是過度繪制帶來的問題。不僅如此,這種計時器頻率的降低也會對電池使用壽命造成負面影響,并會降低其他應用的性能。

這也是為何setTimeout的定時器值推薦最小使用16.7ms的原因(16.7 = 1000 / 60, 即每秒60幀)。

而requestAnimationFrame就是為了解決這個問題而出現的。它所做的事情很簡單,就是跟著瀏覽器的繪制走,如果瀏覽設備繪制間隔是16.7ms,那它就在這個間隔繪制。如果瀏覽設備繪制間隔是10ms,它就10ms繪制。這樣就不會存在過度繪制的問題,動畫不會掉幀,播放自然流暢。

兼容性

2017-04-02_112747.jpg

統一的向下兼容方法:

(function() {
  var lastTime = 0;
  var vendors = ['webkit', 'moz'];
  for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
    window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
    window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] ||    // Webkit中此取消方法的名字變了
    window[vendors[x] + 'CancelRequestAnimationFrame'];
  }

  if (!window.requestAnimationFrame) {
    window.requestAnimationFrame = function(callback, element) {
      var currTime = new Date().getTime();
      var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
      var id = window.setTimeout(function() {
        callback(currTime + timeToCall);
      }, timeToCall);
      lastTime = currTime + timeToCall;
      return id;
    };
  }
  if (!window.cancelAnimationFrame) {
    window.cancelAnimationFrame = function(id) {
        clearTimeout(id);
    };
  }
}());

原文來自:http://www.zhangxinxu.com/wordpress/?p=3695

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容