requestAnimationFrame && setTimeout 原理剖析

就目前來講纽疟,web應(yīng)用實現(xiàn)動畫的方式有很多種斥滤,排除CSS3自帶的transitionanimation動畫屬性烂琴,這里講一下JavaScript實現(xiàn)動畫的其中兩種方法弧械,requestAnimationFrame && setTimeout

  • 前言

在開始分析之前譬挚,我們要了解幾個概念锅铅,視覺暫留 屏幕刷新頻率

1.視覺暫留

??眼睛的另一個重要特是視覺惰,即光象一旦在視網(wǎng)膜上形成减宣,視覺將會對這個光象的感覺維持一個有限的時間盐须,這種生理現(xiàn)象叫做視覺暫留。對于中等亮度的光刺激漆腌,視覺暫留時間約為50ms200ms贼邓。當我們看屏幕的時候,雖然你什么也沒做闷尿,但是屏幕還是以特定的頻率在不停刷新塑径,只是這個刷新過程我們?nèi)庋圩R別到他的細微變化,這就是我們接下來要說的 屏幕刷新頻率

2.屏幕刷新頻率

??我們?nèi)粘5娘@示器填具,一般頻率在60Hz左右统舀,意味著我們的屏幕每1秒需要刷新60次,也就是說每1000ms需要更新60次的屏幕圖像劳景,那么我們由此可以得出誉简,屏幕圖像更新一次所需要的時間間隔也就是16.7ms(1000/60≈16.7)
??由于人的眼睛具有視覺暫留效應(yīng)盟广,且暫留時間為50ms200ms闷串,也就是說人在看屏幕的時候,還沒等到你的大腦印象消失筋量,電腦屏幕就已經(jīng)更新了烹吵,所以這個間隔讓你感覺不到變化碉熄。
??那么屏幕刷新頻率是不是越大越好?我們可以大膽假設(shè)一下年叮,假如我有三個顯示器具被,刷新頻率分別為1Hz玻募、60Hz只损、200Hz、那么對應(yīng)的更新周期時間分別為1000ms七咧、16.7ms跃惫、5ms也就是頻率越大艾栋,圖像更新的間隔就越短爆存,我們看到的畫面就會越穩(wěn)定,當達到一秒更新一次的時候蝗砾,這個時候我們就能夠感覺到明顯的屏幕閃爍先较,帶來視覺疲勞。

顯示器配置信息

3.setTimeout

??setTimeout說白了就是個延時計時器悼粮,通過設(shè)置固定的時間間隔闲勺,從而時間一到,執(zhí)行相應(yīng)的回調(diào)方法扣猫。這個過程不會考慮屏幕刷新頻率菜循,換句話講,它的時間是寫死的申尤。那么為什么會存在丟幀現(xiàn)象發(fā)生癌幕,通俗來說就是為什么使用setTimeout我會感覺到卡頓,畫面不穩(wěn)定昧穿。

??1.setTimeout執(zhí)行的時間與屏幕的刷新頻率不一致會導(dǎo)致丟幀現(xiàn)象勺远。我們不考慮異步問題,假設(shè)我們現(xiàn)在的屏幕設(shè)備是60Hz的刷新頻率时鸵。那么我們圖像的更新周期也就是16.7ms胶逢,我現(xiàn)在的動畫要求是每10ms往下偏移1px,那么這個丟幀現(xiàn)象是如何產(chǎn)生的寥枝?這里我通過一張圖來解釋一下宪塔。

分析圖

分析結(jié)果:
  • 第1次重繪(16.7ms):圖形偏移到1px
  • 第2次重繪(33.4ms):圖形偏移到3px囊拜;丟失1px偏移;
  • 第3次重繪(50.1ms):圖形偏移到4px某筐;
  • 第4次重繪(66.8ms):圖形偏移到6px丟失1px偏移;
  • 第5次重繪(83.5ms):圖形偏移到8px冠跷;丟失1px偏移;
    ......
實驗效果:
實驗效果

??所以根據(jù)分析結(jié)果以及實驗效果南誊,如果setTimeout執(zhí)行的順序與屏幕的刷新頻率不一致身诺,會造成丟幀現(xiàn)象,從而視覺上帶給我們的就是不流暢抄囚。

??2.由于JavaScript屬于單線程霉赡,而setTimeout任務(wù)會被放入異步隊列,通俗來講就是它的執(zhí)行得等一等幔托,具體等什么穴亏,不知道,就是想再等等重挑。只有主線程的任務(wù)執(zhí)行完畢之后嗓化,才會輪到它去執(zhí)行,也就是說我雖然設(shè)置setTimeout 16.7ms間隔去執(zhí)行動畫屬性改變谬哀,但是實際運行的時間可能會有所延遲刺覆。這個延遲可能會導(dǎo)致執(zhí)行的時間與屏幕刷新的時間串掉,造成丟幀史煎。

分析圖

分析結(jié)果:
  • 第1次重繪(16.7ms):圖形未偏移谦屑;應(yīng)該偏移到1px
  • 第2次重繪(33.4ms):圖形偏移到1px應(yīng)該偏移到2px
  • 第3次重繪(50.1ms):圖形偏移到2px篇梭;應(yīng)該偏移到3px
  • 第4次重繪(66.8ms):圖形偏移到3px氢橙;應(yīng)該偏移到4px
  • 第5次重繪(83.5ms):圖形偏移到4px應(yīng)該偏移到5px
    ......
    ??所以根據(jù)分析結(jié)果很洋,我們可以看出充蓝,在異步的現(xiàn)象下,會造成一連串的執(zhí)行差喉磁,從而造成丟幀現(xiàn)象谓苟。

4.requestAnimationFrame

??官方解釋window.requestAnimationFrame()告訴瀏覽器——你希望執(zhí)行一個動畫,并且要求瀏覽器在下次重繪之前調(diào)用指定的回調(diào)函數(shù)更新動畫协怒。該方法需要傳入一個回調(diào)函數(shù)作為參數(shù)涝焙,該回調(diào)函數(shù)會在瀏覽器下一次重繪之前執(zhí)行。也就是說requestAnimationFrame它不需要你去手動設(shè)置執(zhí)行間隔時間孕暇,它是跟隨系統(tǒng)的屏幕刷新頻率走的仑撞,如果屏幕刷新頻率是60Hz,那么它的執(zhí)行間隔就是16.7ms(1000/60≈16.7)妖滔,如果屏幕刷新頻率是100Hz隧哮,那么它的執(zhí)行間隔就是10ms(1000/100=10),這樣就能夠保證它的執(zhí)行與屏幕的刷新頻率保持一致座舍,從而避免丟幀現(xiàn)象沮翔。
??為了提高性能和電池壽命,因此在大多數(shù)瀏覽器里曲秉,當requestAnimationFrame() 運行在后臺標簽頁或者隱藏的<iframe> 里時采蚀,requestAnimationFrame() 會被暫停調(diào)用以提升性能和電池壽命疲牵。

5.requestAnimationFrame Vs setTimeout 區(qū)別

  • requestAnimationFrame在窗口隱藏的時候,會暫停調(diào)用榆鼠,而setTimeout不會暫停纲爸。
  • requestAnimationFrame跟隨系統(tǒng)屏幕刷新頻率,而setTimeout手動配置妆够,會存在丟幀現(xiàn)象识啦。
代碼示例
    var start = 0;
    var element = document.getElementById('SomeElementYouWantToAnimate');
    element.style.position = 'absolute';
    function step() {
        start++;
        element.style.top = start + 'px';
        if (start < 500) {
            window.requestAnimationFrame(step);
        }
    }
    window.requestAnimationFrame(step);

6.附件:requestAnimationFrame Github 兼容降級處理

??源地址:https://github.com/darius/requestAnimationFrame

// Adapted from https://gist.github.com/paulirish/1579671 which derived from 
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating

// requestAnimationFrame polyfill by Erik M?ller.
// Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen Slavi?, Darius Bacon

// MIT license

if (!Date.now)
    Date.now = function() { return new Date().getTime(); };

(function() {
    'use strict';
    
    var vendors = ['webkit', 'moz'];
    for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
        var vp = vendors[i];
        window.requestAnimationFrame = window[vp+'RequestAnimationFrame'];
        window.cancelAnimationFrame = (window[vp+'CancelAnimationFrame']
                                   || window[vp+'CancelRequestAnimationFrame']);
    }
    if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) // iOS6 is buggy
        || !window.requestAnimationFrame || !window.cancelAnimationFrame) {
        var lastTime = 0;
        window.requestAnimationFrame = function(callback) {
            var now = Date.now();
            var nextTime = Math.max(lastTime + 16, now);
            return setTimeout(function() { callback(lastTime = nextTime); },
                              nextTime - now);
        };
        window.cancelAnimationFrame = clearTimeout;
    }
}());
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市责静,隨后出現(xiàn)的幾起案子袁滥,更是在濱河造成了極大的恐慌,老刑警劉巖灾螃,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異揩徊,居然都是意外死亡腰鬼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門塑荒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來熄赡,“玉大人,你說我怎么就攤上這事齿税”肆颍” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵凌箕,是天一觀的道長拧篮。 經(jīng)常有香客問我,道長牵舱,這世上最難降的妖魔是什么串绩? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮芜壁,結(jié)果婚禮上礁凡,老公的妹妹穿的比我還像新娘。我一直安慰自己慧妄,他們只是感情好顷牌,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著塞淹,像睡著了一般窟蓝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上窖铡,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天疗锐,我揣著相機與錄音坊谁,去河邊找鬼。 笑死滑臊,一個胖子當著我的面吹牛口芍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播雇卷,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鬓椭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了关划?” 一聲冷哼從身側(cè)響起小染,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贮折,沒想到半個月后裤翩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡调榄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年踊赠,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片每庆。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡筐带,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缤灵,到底是詐尸還是另有隱情伦籍,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布腮出,位于F島的核電站帖鸦,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏利诺。R本人自食惡果不足惜富蓄,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望慢逾。 院中可真熱鬧立倍,春花似錦、人聲如沸侣滩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽君珠。三九已至寝志,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背材部。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工毫缆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人乐导。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓苦丁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親物臂。 傳聞我的和親對象是個殘疾皇子旺拉,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容