動畫requestAnimationFrame


前言

在研究canvas的2D pixi.js庫的時候,其動畫的刷新都用requestAnimationFrame替代了setTimeout 或 setInterval

但是jQuery中還是采用了setInterval,我這章就研究下順便改造下jQuery的動畫

 

定時器

jQuery動畫的實現考慮到兼容與易用性采用了setInterval來不斷繪制新的屬性值,從而達到動畫的效果。

大部分瀏覽器的顯示頻率是16.7ms,由於瀏覽器的特性,setInterval會有一個丟幀的問題

即使向其傳遞毫秒為單位的參數,它們也不能達到ms的准確性。這是因為javascript是單線程的,可能會發生阻塞

jQuery會有一個全局設置jQuery.fx.interval = 13 設置動畫每秒運行幀數。

默認是13毫秒。該屬性值越小,在速度較快的瀏覽器中(例如,Chrome),動畫執行的越流暢,但是會影響程序的性能並且占用更多的 CPU 資源

那么歸納一點最關鍵的問題:

開發着並不知道下一刻繪制動畫的最佳時機是什么時候

 

requestAnimationFrame

requestAnimationFrame 是專門為實現高性能的幀動畫而設計的一個API

說簡單點

  • setInterval、setTimeout是開發者主動要求瀏覽器去繪制,但是由於種種問題,瀏覽器可能會漏掉部分命令
  • requestAnimationFrame 就是瀏覽器什么要開始繪制了瀏覽器自己知道,通過requestAnimationFrame 告訴開發者,這樣就不會出現重復繪制丟失的問題了

目前已在多個瀏覽器得到了支持,包括IE10+,Firefox,Chrome,Safari,Opera等,在移動設備上,ios6以上版本以及IE mobile 10以上也支持requestAnimationFrame,

唯一比較遺憾的是目前安卓上的原生瀏覽器並不支持requestAnimationFrame,不過對requestAnimationFrame的支持應該是大勢所趨了,安卓版本的chrome 16+也是支持requestAnimationFrame的。

 

比較

區別:

  1. requestAnimationFrame 會把每一幀中的所有DOM操作集中起來,在一次重繪或回流中就完成,並且重繪或回流的時間間隔緊緊跟隨瀏覽器的刷新頻率,一般來說,這個頻率為每秒60幀
  2. 隱藏或不可見的元素中,requestAnimationFrame將不會進行重繪或回流,這當然就意味着更少的的cpu,gpu和內存使用量。
  3. requestAnimationFrame也會像setTimeout一樣有一個返回值ID用於取消,可以把它作為參數傳入cancelAnimationFrame函數來取消requestAnimationFrame的回調

 

兼容處理

摘自HTML5 Canvas 核心技術

window.requestNextAnimationFrame = (function () {
  var originalWebkitRequestAnimationFrame = undefined,
      wrapper = undefined,
      callback = undefined,
      geckoVersion = 0,
      userAgent = navigator.userAgent,
      index = 0,
      self = this;

  // Workaround for Chrome 10 bug where Chrome
  // does not pass the time to the animation function

  if (window.webkitRequestAnimationFrame) {
    // Define the wrapper

    wrapper = function (time) {
      if (time === undefined) {
        time = +new Date();
      }
      self.callback(time);
    };

    // Make the switch

    originalWebkitRequestAnimationFrame = window.webkitRequestAnimationFrame;

    window.webkitRequestAnimationFrame = function (callback, element) {
      self.callback = callback;

      // Browser calls the wrapper and wrapper calls the callback

      originalWebkitRequestAnimationFrame(wrapper, element);
    }
  }

  // Workaround for Gecko 2.0, which has a bug in
  // mozRequestAnimationFrame() that restricts animations
  // to 30-40 fps.

  if (window.mozRequestAnimationFrame) {
    // Check the Gecko version. Gecko is used by browsers
    // other than Firefox. Gecko 2.0 corresponds to
    // Firefox 4.0.

    index = userAgent.indexOf('rv:');

    if (userAgent.indexOf('Gecko') != -1) {
      geckoVersion = userAgent.substr(index + 3, 3);

      if (geckoVersion === '2.0') {
        // Forces the return statement to fall through
        // to the setTimeout() function.

        window.mozRequestAnimationFrame = undefined;
      }
    }
  }

  return  window.requestAnimationFrame ||
      window.webkitRequestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      window.oRequestAnimationFrame ||
      window.msRequestAnimationFrame ||

      function (callback, element) {
        var start,
            finish;

        window.setTimeout(function () {
          start = +new Date();
          callback(start);
          finish = +new Date();

          self.timeout = 1000 / 60 - (finish - start);

        }, self.timeout);
      };
}());

  window.cancelNextRequestAnimationFrame = window.cancelRequestAnimationFrame
    || window.webkitCancelAnimationFrame
    || window.webkitCancelRequestAnimationFrame
    || window.mozCancelRequestAnimationFrame
    || window.oCancelRequestAnimationFrame
    || window.msCancelRequestAnimationFrame
    || clearTimeout;

 

對比

通過requestAnimationFrame與setInterval同樣的效果對比

一段動畫采用setInterval與requestAnimationFrame,分別給出了webKit下調用刷新的次數

setInterval實現,調用了144次左右


 

requestAnimationFrame 實現調用了120次左右


 

通過對比,在同樣的時間里,通過定時器刷新的次數是要更多,當然定時器跟設置的時間是有關系的

這里我要強調一點,有效值,就是我們在瀏覽器能接受的范圍內,給出一個最佳的渲染時間,這樣才是一個性能優化的最佳的選擇

 


免責聲明!

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



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