容易被忽視的RequestAnimationFrame

傳統(tǒng)的JS動畫都是用 setTimeout 和 setInterval 實(shí)現(xiàn)的,后來無意中在網(wǎng)上看到一個(gè)新的JS函數(shù) requestAnimationFrame 用它來替代傳統(tǒng)的JS動畫方法,說是效果更好,當(dāng)時(shí)也沒有仔細(xì)深究。直到昨天去魅族面試的時(shí)候,面試官問我有什么新的辦法可以替代傳統(tǒng)的JS動畫,我說“我知道一個(gè)叫 requestAnimationFrame 的函數(shù),它的執(zhí)行效果更好”。但是讓我仔細(xì)描述的時(shí)候,我就說不下去了,這也是我寫這篇博客的初衷,我們學(xué)習(xí)的過程中一定要知其然比知其所以然,不要什么都略懂,最后落得跟半吊子一樣。

定時(shí)器一直都是JS動畫的核心技術(shù)。而編寫動畫循環(huán)的關(guān)鍵是要知道延遲時(shí)間多長合適。一方面,循環(huán)間隔必須足夠短,這樣才能讓不同的動畫效果顯得平滑流暢;另一方面,循環(huán)間隔還要足夠長,才能確保瀏覽器有能力渲染產(chǎn)生的變化。

大多數(shù)電腦顯示器的刷新頻率是60HZ,也就是每秒鐘重繪60次。大多數(shù)瀏覽器都會對重繪操作加以限制,不超過顯示器的重繪頻率,因?yàn)榧词钩^那個(gè)頻率用戶體驗(yàn)也不會提升。因此,最平滑動畫的最佳循環(huán)間隔是 1000ms / 60 ,約為16.7ms。

傳統(tǒng)的 setTimeout 和 setInterval 它們都不是很精確,因?yàn)樗鼈儗?shí)際上只是把動畫代碼添加到瀏覽器UI線程隊(duì)尾以等待執(zhí)行時(shí)間,如果它們前面有其它任務(wù),則必須等前面的任務(wù)執(zhí)行完在執(zhí)行動畫代碼。

而 requestAnimationFrame 采用系統(tǒng)時(shí)間間隔,讓各種動畫效果能夠有一個(gè)統(tǒng)一的刷新機(jī)制,從而節(jié)省系統(tǒng)資源,提高系統(tǒng)性能,改善視覺效果。它有如下三個(gè)特點(diǎn):

  • 會把每一幀中所有的DOM操作集中起來,在一次動畫操作就完成,并且動畫的時(shí)間間隔緊緊跟隨瀏覽器的刷新頻率(不需要設(shè)置時(shí)間間隔)。
  • 在隱藏或者不可見的元素中,不會進(jìn)行動畫操作。
  • 當(dāng)瀏覽器不是激活狀態(tài),不會進(jìn)行動畫操作。

下面是一個(gè)兼容所有瀏覽器的使用 requestAnimationFrame 的代碼(IE9-無該方法)

(function() {
    var lastTime = 0;
    var vendors = ['ms', 'moz', 'webkit', 'o'];
    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; x++) {
        window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
        window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || 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 = setTimeout(function() {
                callback(currTime + timeToCall);
            }, timeToCall);
            lastTime = currTime + timeToCall;
            return id;
        }
    }
    if (!window.cancelAnimationFrame) {
        window.cancelAnimationFrame = function(id) {
            clearTimeout(id);
        }
    }
}());

最后附上我利用 requestAnimationFrame 制作的一個(gè) 跳動的小球 的DEMO。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一:在制作一個(gè)Web應(yīng)用或Web站點(diǎn)的過程中,你是如何考慮他的UI、安全性、高性能、SEO、可維護(hù)性以及技術(shù)因素的...
    Arno_z閱讀 1,354評論 0 1
  • requestAnimationFrame這個(gè)API,可能很多人都聽過,但并沒有真正用過。MDN上的解釋是: wi...
    Perkin_閱讀 3,607評論 0 4
  • 看了很多視頻、文章,最后卻通通忘記了,別人的知識依舊是別人的,自己卻什么都沒獲得。此系列文章旨在加深自己的印象,因...
    DCbryant閱讀 819評論 0 2
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,036評論 4 61
  • 晚上,許林一陪著翩翩打點(diǎn)滴。翩翩的高燒退了,精神略微恢復(fù)的她不再老老實(shí)實(shí)地坐在座位上,她在自己的活動范圍內(nèi)釋放著還...
    梅花貓閱讀 666評論 1 2

友情鏈接更多精彩內(nèi)容