一文詳解requestAnimationFrame請(qǐng)求動(dòng)畫幀
1.定義
它是一個(gè)瀏覽器的宏任務(wù)。 requestAnimationFrame的用法與setTimeout、setInterval很相似,只是不需要設(shè)置時(shí)間間隔而已。requestAnimationFrame使用一個(gè)回調(diào)函數(shù)作為參數(shù),這個(gè)回調(diào)函數(shù)會(huì)在瀏覽器重繪之前調(diào)用。它返回一個(gè)整數(shù),表示定時(shí)器的編號(hào),這個(gè)值可以傳遞給cancelAnimationFrame用于取消這個(gè)函數(shù)的執(zhí)行。
2.特點(diǎn)
requestAnimationFrame特點(diǎn): 、
【1】requestAnimationFrame會(huì)把每一幀中的所有DOM操作集中起來(lái),在一次重繪或回流中就完成,并且重繪或回流的時(shí)間間隔緊緊跟隨瀏覽器的刷新頻率。
【2】在隱藏或不可見(jiàn)的元素中,requestAnimationFrame將不會(huì)進(jìn)行重繪或回流,這當(dāng)然就意味著更少的CPU、GPU和內(nèi)存使用量。
【3】requestAnimationFrame是由瀏覽器專門為動(dòng)畫提供的API,在運(yùn)行時(shí)瀏覽器會(huì)自動(dòng)優(yōu)化方法的調(diào)用,并且如果頁(yè)面不是激活狀態(tài)下的話,動(dòng)畫會(huì)自動(dòng)暫停,有效節(jié)省了CPU開(kāi)銷
3.瀏覽器動(dòng)畫原理
要真正理解requestAnimationFrame的優(yōu)勢(shì)首先要清楚瀏覽器動(dòng)畫的基本實(shí)現(xiàn)思路。實(shí)際上就是在前端運(yùn)行一個(gè)頻繁觸發(fā)的函數(shù),這個(gè)函數(shù)每次運(yùn)行時(shí)都是更新物體的位置屬性,比如每次都沿X方向每次都會(huì)加1,當(dāng)這個(gè)函數(shù)的觸發(fā)頻率足夠高,人眼就不會(huì)有任何察覺(jué),因此顯示在屏幕上的效果就是流暢的動(dòng)畫了。
4. CSS3動(dòng)畫和JS動(dòng)畫的比較
·CSS動(dòng)畫優(yōu)點(diǎn)
【1】在Chromium基礎(chǔ)上的瀏覽器中
【2】同時(shí)CSS動(dòng)畫不觸發(fā)layout或paint,在CSS動(dòng)畫或JS動(dòng)畫觸發(fā)了paint或layout時(shí),需要main thread進(jìn)行Layer樹(shù)的重計(jì)算,這時(shí)CSS動(dòng)畫或JS動(dòng)畫都會(huì)阻塞后續(xù)操作。
【3】部分情況下瀏覽器可以對(duì)動(dòng)畫進(jìn)行優(yōu)化(比如專門新建一個(gè)圖層用來(lái)跑動(dòng)畫)。
【4】 部分效果可以強(qiáng)制使用硬件加速 (通過(guò) GPU 來(lái)提高動(dòng)畫性能)
·CSS動(dòng)畫缺點(diǎn)
【1】代碼冗長(zhǎng)。
【2】CSS 實(shí)現(xiàn)稍微復(fù)雜一點(diǎn)動(dòng)畫,CSS代碼可能都會(huì)變得非常笨重; 運(yùn)行過(guò)程控制較弱。
【3】css3動(dòng)畫只能在某些場(chǎng)景下控制動(dòng)畫的暫停與繼續(xù),不能在特定的位置添加回調(diào)函數(shù)。
·JS動(dòng)畫優(yōu)點(diǎn)
【1】JS動(dòng)畫控制能力強(qiáng),可以在動(dòng)畫播放過(guò)程中對(duì)動(dòng)畫進(jìn)行精細(xì)控制,如開(kāi)始、暫停、終止、取消等;
【2】JS動(dòng)畫效果比CSS3動(dòng)畫豐富,功能涵蓋面廣,比如可以實(shí)現(xiàn)曲線運(yùn)動(dòng)、沖擊閃爍、視差滾動(dòng)等CSS難以實(shí)現(xiàn)的效果;
【3】JS動(dòng)畫大多數(shù)情況下沒(méi)有兼容性問(wèn)題,而CSS3動(dòng)畫有兼容性問(wèn)題;
·JS動(dòng)畫缺點(diǎn)
【1】JS在瀏覽器的主線程中運(yùn)行,而主線程中還有其它需要運(yùn)行的JS腳本、樣式計(jì)算、布局、繪制任務(wù)等,對(duì)其干擾可能導(dǎo)致線程出現(xiàn)阻塞,從而造成丟幀的情況;
【2】 對(duì)于幀速表現(xiàn)不好的低版本瀏覽器,CSS3可以做到自然降級(jí),而JS則需要撰寫額外代碼;
【3】 JS動(dòng)畫往往需要頻繁操作DOM的css屬性來(lái)實(shí)現(xiàn)視覺(jué)上的動(dòng)畫效果,這個(gè)時(shí)候?yàn)g覽器要不停地執(zhí)行重繪和重排,這對(duì)于性能的消耗是很大的,尤其是在分配給瀏覽器的內(nèi)存沒(méi)那么寬裕的移動(dòng)端。
5. setTimeout 、setInterval、requestAnimationFrame區(qū)別
1》setInterval
運(yùn)行機(jī)制:
按照指定的周期(以毫秒計(jì))來(lái)調(diào)用函數(shù)或計(jì)算表達(dá)式。方法會(huì)不停地調(diào)用函數(shù)(當(dāng)頁(yè)面被隱藏或者最小化時(shí),setInterval()仍在后臺(tái)繼續(xù)執(zhí)行,這種動(dòng)畫刷新是完全沒(méi)有意義的,對(duì)cpu也是極大的浪費(fèi)),直到 clearInterval() 被調(diào)用或窗口被關(guān)閉。 setinterval的執(zhí)行時(shí)間不確定,參數(shù)中的時(shí)間間隔是將代碼添加到異步隊(duì)列中等待的時(shí)間。只有當(dāng)主線程中的任務(wù)以及隊(duì)列前面的任務(wù)是執(zhí)行完畢,才真正開(kāi)始執(zhí)行動(dòng)畫代碼。
缺點(diǎn):
(1)setinterval()無(wú)視代碼錯(cuò)誤,如果setinterval執(zhí)行的代碼由于某種原因出了錯(cuò),它還會(huì)持續(xù)不斷地調(diào)用該代碼。
(2)setinterval無(wú)視網(wǎng)絡(luò)延遲,由于某些原因(服務(wù)器過(guò)載、臨時(shí)斷網(wǎng)、流量劇增、用戶帶寬受限,等等),你的請(qǐng)求要花的時(shí)間遠(yuǎn)比你想象的要長(zhǎng)。但setinterval不在乎。它仍然會(huì)按定時(shí)持續(xù)不斷地觸發(fā)請(qǐng)求,最終你的客戶端網(wǎng)絡(luò)隊(duì)列會(huì)塞滿調(diào)用函數(shù)。
(3) setinterval不保證執(zhí)行,與settimeout不同,并不能保證到了時(shí)間間隔,代碼就準(zhǔn)能執(zhí)行。如果你調(diào)用的函數(shù)需要花很長(zhǎng)時(shí)間才能完成,那某些調(diào)用會(huì)被直接忽略。
2》setTimeout
運(yùn)行機(jī)制:
在指定的毫秒數(shù)后調(diào)用函數(shù)或計(jì)算表達(dá)式。每次函數(shù)執(zhí)行的時(shí)候都會(huì)創(chuàng)建換一個(gè)新的定時(shí)器。在前一個(gè)定時(shí)器代碼執(zhí)行完之前,不會(huì)向隊(duì)列插入新的定時(shí)器代碼,確保不會(huì)有任何確實(shí)的間隔。并且確保在下一次定時(shí)器代碼執(zhí)行之前,至少要等待指定的間隔,避免了連續(xù)的運(yùn)行。當(dāng)方法執(zhí)行完成定時(shí)器就立即停止(但是定時(shí)器還在,只不過(guò)沒(méi)用了).
缺點(diǎn):
(1)利用seTimeout實(shí)現(xiàn)的動(dòng)畫在某些低端機(jī)上會(huì)出現(xiàn)卡頓、抖動(dòng)的現(xiàn)象。
(2)settimeout的執(zhí)行時(shí)間并不是確定的。在js中, settimeout 任務(wù)被放進(jìn)了異步隊(duì)列中,只有當(dāng)主線程上的任務(wù)執(zhí)行完以后,才會(huì)去檢查該隊(duì)列里的任務(wù)是否需要開(kāi)始執(zhí)行,因此 settimeout 的實(shí)際執(zhí)行時(shí)間一般要比其設(shè)定的時(shí)間晚一些。
(3)刷新頻率受屏幕分辨率和屏幕尺寸的影響,因此不同設(shè)備的屏幕刷新頻率可能會(huì)不同,而 settimeout只能設(shè)置一個(gè)固定的時(shí)間間隔,這個(gè)時(shí)間不一定和屏幕的刷新時(shí)間相同。
(4)settimeout的執(zhí)行只是在內(nèi)存中對(duì)圖像屬性進(jìn)行改變,這個(gè)變化必須要等到屏幕下次刷新時(shí)才會(huì)被更新到屏幕上。如果兩者的步調(diào)不一致,就可能會(huì)導(dǎo)致中間某一幀的操作被跨越過(guò)去,而直接更新下一幀的圖像。
3》requestAnimationFrame
缺點(diǎn): requestanimationframe 不管理回調(diào)函數(shù),即在回調(diào)被執(zhí)行前,多次調(diào)用帶有同一回調(diào)函數(shù)的 requestanimationframe,會(huì)導(dǎo)致回調(diào)在同一幀中執(zhí)行多次。
解決辦法: 對(duì)于這種高頻發(fā)事件,一般的解決方法是使用節(jié)流函數(shù)。但是在這里使用節(jié)流函數(shù)并不能完美解決問(wèn)題。因?yàn)楣?jié)流函數(shù)是通過(guò)時(shí)間管理隊(duì)列的,完美的解決方案是通過(guò) requestanimationframe 來(lái)管理隊(duì)列,其思路就是保證 requestanimationframe 的隊(duì)列里,同樣的回調(diào)函數(shù)只有一個(gè)。
4》與setTimeout和setInterval的區(qū)別
【1】執(zhí)行次數(shù):setInterval執(zhí)行多次,setTimeout、requestAnimationframe執(zhí)行一次
【2】性能:setTimeout會(huì)出現(xiàn)丟幀、卡頓現(xiàn)象,setInterval會(huì)出現(xiàn)調(diào)用丟失情況,requestAnimationframe不會(huì)出現(xiàn)這些問(wèn)題,頁(yè)面未激活時(shí)不會(huì)執(zhí)行動(dòng)畫,減少了大量cpu消耗
【3】兼容性問(wèn)題:setInterval,setTimeout在IE瀏覽器中不支持參數(shù)傳遞,能夠在大多數(shù)瀏覽器中正常使用。而requestAnimationframe不兼容IE10以下.
5》requestAnimationFrame補(bǔ)充
除了上文提到的requestAnimationFrame的優(yōu)勢(shì)外,requestAnimationFrame還有以下兩個(gè)優(yōu)勢(shì):
【1】CPU節(jié)能:使用setTimeout實(shí)現(xiàn)的動(dòng)畫,當(dāng)頁(yè)面被隱藏或最小化時(shí),setTimeout 仍然在后臺(tái)執(zhí)行動(dòng)畫任務(wù),由于此時(shí)頁(yè)面處于不可見(jiàn)或不可用狀態(tài),刷新動(dòng)畫是沒(méi)有意義的,完全是浪費(fèi)CPU資源。而requestAnimationFrame則完全不同,當(dāng)頁(yè)面處于未激活的狀態(tài)下,該頁(yè)面的屏幕刷新任務(wù)也會(huì)被系統(tǒng)暫停,因此跟著系統(tǒng)步伐走的requestAnimationFrame也會(huì)停止渲染,當(dāng)頁(yè)面被激活時(shí),動(dòng)畫就從上次停留的地方繼續(xù)執(zhí)行,有效節(jié)省了CPU開(kāi)銷。
【2】函數(shù)節(jié)流:在高頻率事件(resize,scroll等)中,為了防止在一個(gè)刷新間隔內(nèi)發(fā)生多次函數(shù)執(zhí)行,使用requestAnimationFrame可保證每個(gè)刷新間隔內(nèi),函數(shù)只被執(zhí)行一次,這樣既能保證流暢性,也能更好的節(jié)省函數(shù)執(zhí)行的開(kāi)銷。一個(gè)刷新間隔內(nèi)函數(shù)執(zhí)行多次是沒(méi)有意義的,因?yàn)轱@示器每16.7ms刷新一次,多次繪制并不會(huì)在屏幕上體現(xiàn)出來(lái)。
5.應(yīng)用場(chǎng)景
【1】監(jiān)聽(tīng) scroll 函數(shù) 頁(yè)面滾動(dòng)事件(scroll)的監(jiān)聽(tīng)函數(shù),就很適合用這個(gè) api,推遲到下一次重新渲染。
【2】大量數(shù)據(jù)渲染 比如對(duì)十萬(wàn)條數(shù)據(jù)進(jìn)行渲染,主要由以下幾種方法:
(1)使用定時(shí)器
(2)使用 requestAnimationFrame
【3】監(jiān)控卡頓方法 :每秒中計(jì)算一次網(wǎng)頁(yè)的 FPS(畫面每秒傳輸幀數(shù)),獲得一列數(shù)據(jù),然后分析。通俗地解釋就是,通過(guò) requestAnimationFrame API 來(lái)定時(shí)執(zhí)行一些 JS 代碼,如果瀏覽器卡頓,無(wú)法很好地保證渲染的頻率,1s 中 frame 無(wú)法達(dá)到 60 幀,即可間接地反映瀏覽器的渲染幀率。
總結(jié)
到此這篇關(guān)于requestAnimationFrame請(qǐng)求動(dòng)畫幀的文章就介紹到這了,更多相關(guān)requestAnimationFrame請(qǐng)求動(dòng)畫幀內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
npm?install報(bào)錯(cuò)Error:EPERM:operation?not?permitted,rename解決
這篇文章主要給大家介紹了關(guān)于npm?install報(bào)錯(cuò)Error:EPERM:operation?not?permitted,rename的解決辦法,文中介紹了可能遇到的多種原因以及解決辦法,需要的朋友可以參考下2024-01-01利用JavaScript實(shí)現(xiàn)3D可旋轉(zhuǎn)粒子矩陣效果
dat.gui.js是一個(gè)一個(gè)輕量級(jí)的圖形用戶界面庫(kù),或者說(shuō)GUI組件,只有幾十KB,可以用于創(chuàng)建操作控制三維場(chǎng)景的菜單欄等。本文將利用dat.gui.min.js實(shí)現(xiàn)3D可旋轉(zhuǎn)粒子矩陣效果,感興趣的可以了解一下2022-06-06JS實(shí)現(xiàn)向表格中動(dòng)態(tài)添加行的方法
這篇文章主要介紹了JS實(shí)現(xiàn)向表格中動(dòng)態(tài)添加行的方法,涉及javascript針對(duì)表格行的動(dòng)態(tài)添加技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-03-03javascript實(shí)現(xiàn)圖片上傳前臺(tái)頁(yè)面
這篇文章主要介紹使用javascript實(shí)現(xiàn)圖片上傳并在前臺(tái)頁(yè)面顯示,代碼很簡(jiǎn)單,需要的朋友可以參考下2015-08-08JS實(shí)現(xiàn)文字向下滾動(dòng)完整實(shí)例
這篇文章主要介紹了JS實(shí)現(xiàn)文字向下滾動(dòng)的方法,以一個(gè)完整實(shí)例形式詳細(xì)分析了html頁(yè)面布局、css樣式及對(duì)應(yīng)的js滾動(dòng)功能實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-02-02Pixi.js實(shí)現(xiàn)可視化圖形編輯器的方法
本文主要介紹了Pixi.js實(shí)現(xiàn)可視化圖形編輯器的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03