關於 requestAnimationFrame 小結

1、小談 requestAnimationFrame:css

提及 requestAnimationFrame,咱們先看幅圖:html

 

 至關一部分的瀏覽器的顯示頻率是16.7ms, 就是上圖第一行的節奏,表現就是「我和你一步兩步三步四步往前走……」。若是咱們火力搞猛一點,例如搞個10ms setTimeout,就會是下面一行的模樣——每第三個圖形都沒法繪製(紅色箭頭指示),表現就是「我和你一步兩步 坑四步往前走……」。css3

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

一樣的,顯示器16.7ms刷新間隔以前發生了其餘繪製請求(setTimeout),致使全部第三幀丟失,繼而致使動畫斷續顯示(堵車的感受),這就是過分繪製帶來的問題。不只如此,這種計時器頻率的下降也會對電池使用壽命形成負面影響,並會下降其餘應用的性能。github

這也是爲什麼setTimeout的定時器值推薦最小使用16.7ms的緣由(16.7 = 1000 / 60, 即每秒60幀)。web

而我requestAnimationFrame就是爲了這個而出現的。它所作的事情很簡單,跟着瀏覽器的繪製走,若是瀏覽設備繪製間隔是16.7ms,那我就這個間隔繪製;若是瀏覽設備繪製間隔是10ms, 我就10ms繪製。這樣就不會存在過分繪製的問題,動畫不會掉幀,天然流暢的說~~canvas

內部是這麼運做的:
瀏覽器(如頁面)每次要洗澡(重繪),就會通知我(requestAnimationFrame):小丸子,我要洗澡了,你能夠跟我一塊兒洗哦!promise

這是資源很是高效的一種利用方式。怎麼講呢?瀏覽器

  1. 就算不少個小丸子要一塊兒洗澡,瀏覽器只要通知一次就能夠了。而setTimeout貌似是多個獨立繪製。
  2. 頁面最小化了,或者被Tab切換關燈了。頁面是不會洗澡的,天然,小丸子也不會洗澡的(沒通知啊)。頁面繪製所有中止,資源高效利用。

2、兼容性:異步

 

因此,requestAnimationFrame 一個簡單的兼容性代碼以下:

(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);
        };
    }
}());

3、動畫效果:

css3 能夠實現不少動畫效果,貝塞爾曲線是一個標準3次方曲線(詳見:貝塞爾曲線與CSS3動畫、SVG和canvas的基情),所以,只能是:LinearSineQuadCubicExpo等,以下圖:

 

但 css3 對於 BackBounce等緩動則只可觀望而不可褻玩焉。

先看一個效果:小球彈起落地效果 (此例結合了 Tweenjs 庫)

動畫核心代碼以下:

funFall = function() {
    var start = 0, during = 100;
    var _run = function() {
         start++;
         var top = Tween.Bounce.easeOut(start, objBall.top, 500 - objBall.top, during);
         ball.css("top", top);
         shadowWithBall(top);    // 投影跟隨小球的動
         if (start < during) requestAnimationFrame(_run);
    };
    _run();
};

4、深究 requestAnimationFrame:

事件循環和任務隊列機制裏邊,牽扯到 setTimeout,在討論瀏覽器刷新頻率的時候,常常將 setTimeout和 requestAnimationFarme做比較。

那麼,requestAnimationFarme是否也屬於異步任務,若是是的話,是屬於macro-task仍是micro-task?

關於macro-task 和 micro-task:

一、macrotasks包含:主js、UI渲染、setTimeout、setInterval、setImmediate、requestAnimationFarme、I/O等
二、microtasks包含:process.nextTick、promise、Object.observe等

具體詳見:

從Promise來看JavaScript中的Event Loop、Tasks和Microtasks

理解事件循環一(淺析)

Promise的隊列與setTimeout的隊列有何關聯

 

參考連接:https://www.zhangxinxu.com/wordpress/2013/09/css3-animation-requestanimationframe-tween-%e5%8a%a8%e7%94%bb%e7%ae%97%e6%b3%95/

相關文章
相關標籤/搜索