一、初識(shí)requestAnimationFrame
requestAnimationFrame解決了瀏覽器不知道javascript動(dòng)畫(huà)什么時(shí)候開(kāi)始、不知道最佳循環(huán)間隔時(shí)間的問(wèn)題。它是跟著瀏覽器的繪制走的,如果瀏覽器繪制間隔是16.7ms,它就按這個(gè)間隔繪制;如果瀏覽器繪制間隔是10ms, 它就按10ms繪制。這樣就不會(huì)存在過(guò)度繪制的問(wèn)題,動(dòng)畫(huà)不會(huì)丟幀。
內(nèi)部是這么運(yùn)作的:
瀏覽器頁(yè)面每次要重繪,就會(huì)通知requestAnimationFrame;
這是資源非常高效的一種利用方式。
怎么講呢?
有以下兩點(diǎn):
1、就算很多個(gè)requestAnimationFrame()要執(zhí)行,瀏覽器只要通知一次就可以了。而setTimeout是多個(gè)獨(dú)立繪制。
2、一旦頁(yè)面不出于當(dāng)前頁(yè)面(比如:頁(yè)面最小化了),頁(yè)面是不會(huì)進(jìn)行重繪的,自然requestAnimationFrame也不會(huì)觸發(fā)(因?yàn)闆](méi)有通知)。頁(yè)面繪制全部停止,資源高效利用。
編
二. 動(dòng)畫(huà)的循環(huán)間隔
編寫(xiě)動(dòng)畫(huà)循環(huán)的關(guān)鍵,是要知道延遲時(shí)間多長(zhǎng)合適。一方面,循環(huán)時(shí)間必須足夠短,這樣才能保證動(dòng)畫(huà)效果更平滑流暢;另一方面,循環(huán)還要足夠長(zhǎng),這樣才能保證瀏覽器有能力渲染產(chǎn)生的變化。大多數(shù)顯示器的刷新頻率是60Hz,相當(dāng)于每秒鐘重繪60次。大多數(shù)瀏覽器都會(huì)對(duì)重繪操作加以限制,不超過(guò)顯示器的重繪頻率,因?yàn)榧词钩^(guò)了這個(gè)頻率,用戶體驗(yàn)也不會(huì)有提升。
因此最平滑動(dòng)畫(huà)的最佳循環(huán)間隔是1000ms/60,約等于17ms。以這個(gè)循環(huán)間隔重繪的動(dòng)畫(huà)是平滑的,因?yàn)檫@個(gè)速度最接近瀏覽器的最高限速。為了適應(yīng)17ms的循環(huán)間隔,多重動(dòng)畫(huà)可能需要加以節(jié)制,以便不會(huì)完成得太快。
雖然與使用多組setTimeout()相比,使用setInterval()的動(dòng)畫(huà)循環(huán)效率更高。但是無(wú)論setTimeout()還是setInterval()都不十分精確。為它們傳入的第二個(gè)參數(shù),實(shí)際上只是指定了把動(dòng)畫(huà)代碼添加到瀏覽器UI線程隊(duì)列以等待執(zhí)行的時(shí)間。如果隊(duì)列前面已經(jīng)加入了其他任務(wù),那動(dòng)畫(huà)代碼就要等前面的任務(wù)執(zhí)行完成后再執(zhí)行。如果UI線程繁忙,比如忙于處理用戶操作,那么即使把代碼加入隊(duì)列也不會(huì)立即執(zhí)行。
因此,知道什么時(shí)候繪制下一幀是保證動(dòng)畫(huà)平滑的關(guān)鍵。然而,面對(duì)不十分精確的setTimeout()和setInterval() ,開(kāi)發(fā)人員至今都沒(méi)有辦法確保瀏覽器按時(shí)繪制下一幀。
以下是幾個(gè)瀏覽器的計(jì)時(shí)器精度:
IE8及其以下版本瀏覽器: 15.6ms;
IE9及其以上版本瀏覽器:4ms;
Firefox和Safari:10ms;
Chrome:4ms。
新聞熱點(diǎn)
疑難解答
圖片精選