一文詳解requestAnimationFrame請求動畫幀
1.定義
它是一個瀏覽器的宏任務(wù)。 requestAnimationFrame的用法與setTimeout、setInterval很相似,只是不需要設(shè)置時間間隔而已。requestAnimationFrame使用一個回調(diào)函數(shù)作為參數(shù),這個回調(diào)函數(shù)會在瀏覽器重繪之前調(diào)用。它返回一個整數(shù),表示定時器的編號,這個值可以傳遞給cancelAnimationFrame用于取消這個函數(shù)的執(zhí)行。
2.特點(diǎn)
requestAnimationFrame特點(diǎn): 、
【1】requestAnimationFrame會把每一幀中的所有DOM操作集中起來,在一次重繪或回流中就完成,并且重繪或回流的時間間隔緊緊跟隨瀏覽器的刷新頻率。
【2】在隱藏或不可見的元素中,requestAnimationFrame將不會進(jìn)行重繪或回流,這當(dāng)然就意味著更少的CPU、GPU和內(nèi)存使用量。
【3】requestAnimationFrame是由瀏覽器專門為動畫提供的API,在運(yùn)行時瀏覽器會自動優(yōu)化方法的調(diào)用,并且如果頁面不是激活狀態(tài)下的話,動畫會自動暫停,有效節(jié)省了CPU開銷
3.瀏覽器動畫原理
要真正理解requestAnimationFrame的優(yōu)勢首先要清楚瀏覽器動畫的基本實(shí)現(xiàn)思路。實(shí)際上就是在前端運(yùn)行一個頻繁觸發(fā)的函數(shù),這個函數(shù)每次運(yùn)行時都是更新物體的位置屬性,比如每次都沿X方向每次都會加1,當(dāng)這個函數(shù)的觸發(fā)頻率足夠高,人眼就不會有任何察覺,因此顯示在屏幕上的效果就是流暢的動畫了。
4. CSS3動畫和JS動畫的比較
·CSS動畫優(yōu)點(diǎn)
【1】在Chromium基礎(chǔ)上的瀏覽器中
【2】同時CSS動畫不觸發(fā)layout或paint,在CSS動畫或JS動畫觸發(fā)了paint或layout時,需要main thread進(jìn)行Layer樹的重計(jì)算,這時CSS動畫或JS動畫都會阻塞后續(xù)操作。
【3】部分情況下瀏覽器可以對動畫進(jìn)行優(yōu)化(比如專門新建一個圖層用來跑動畫)。
【4】 部分效果可以強(qiáng)制使用硬件加速 (通過 GPU 來提高動畫性能)
·CSS動畫缺點(diǎn)
【1】代碼冗長。
【2】CSS 實(shí)現(xiàn)稍微復(fù)雜一點(diǎn)動畫,CSS代碼可能都會變得非常笨重; 運(yùn)行過程控制較弱。
【3】css3動畫只能在某些場景下控制動畫的暫停與繼續(xù),不能在特定的位置添加回調(diào)函數(shù)。
·JS動畫優(yōu)點(diǎn)
【1】JS動畫控制能力強(qiáng),可以在動畫播放過程中對動畫進(jìn)行精細(xì)控制,如開始、暫停、終止、取消等;
【2】JS動畫效果比CSS3動畫豐富,功能涵蓋面廣,比如可以實(shí)現(xiàn)曲線運(yùn)動、沖擊閃爍、視差滾動等CSS難以實(shí)現(xiàn)的效果;
【3】JS動畫大多數(shù)情況下沒有兼容性問題,而CSS3動畫有兼容性問題;
·JS動畫缺點(diǎn)
【1】JS在瀏覽器的主線程中運(yùn)行,而主線程中還有其它需要運(yùn)行的JS腳本、樣式計(jì)算、布局、繪制任務(wù)等,對其干擾可能導(dǎo)致線程出現(xiàn)阻塞,從而造成丟幀的情況;
【2】 對于幀速表現(xiàn)不好的低版本瀏覽器,CSS3可以做到自然降級,而JS則需要撰寫額外代碼;
【3】 JS動畫往往需要頻繁操作DOM的css屬性來實(shí)現(xiàn)視覺上的動畫效果,這個時候?yàn)g覽器要不停地執(zhí)行重繪和重排,這對于性能的消耗是很大的,尤其是在分配給瀏覽器的內(nèi)存沒那么寬裕的移動端。
5. setTimeout 、setInterval、requestAnimationFrame區(qū)別
1》setInterval
運(yùn)行機(jī)制:
按照指定的周期(以毫秒計(jì))來調(diào)用函數(shù)或計(jì)算表達(dá)式。方法會不停地調(diào)用函數(shù)(當(dāng)頁面被隱藏或者最小化時,setInterval()仍在后臺繼續(xù)執(zhí)行,這種動畫刷新是完全沒有意義的,對cpu也是極大的浪費(fèi)),直到 clearInterval() 被調(diào)用或窗口被關(guān)閉。 setinterval的執(zhí)行時間不確定,參數(shù)中的時間間隔是將代碼添加到異步隊(duì)列中等待的時間。只有當(dāng)主線程中的任務(wù)以及隊(duì)列前面的任務(wù)是執(zhí)行完畢,才真正開始執(zhí)行動畫代碼。
缺點(diǎn):
(1)setinterval()無視代碼錯誤,如果setinterval執(zhí)行的代碼由于某種原因出了錯,它還會持續(xù)不斷地調(diào)用該代碼。
(2)setinterval無視網(wǎng)絡(luò)延遲,由于某些原因(服務(wù)器過載、臨時斷網(wǎng)、流量劇增、用戶帶寬受限,等等),你的請求要花的時間遠(yuǎn)比你想象的要長。但setinterval不在乎。它仍然會按定時持續(xù)不斷地觸發(fā)請求,最終你的客戶端網(wǎng)絡(luò)隊(duì)列會塞滿調(diào)用函數(shù)。
(3) setinterval不保證執(zhí)行,與settimeout不同,并不能保證到了時間間隔,代碼就準(zhǔn)能執(zhí)行。如果你調(diào)用的函數(shù)需要花很長時間才能完成,那某些調(diào)用會被直接忽略。
2》setTimeout
運(yùn)行機(jī)制:
在指定的毫秒數(shù)后調(diào)用函數(shù)或計(jì)算表達(dá)式。每次函數(shù)執(zhí)行的時候都會創(chuàng)建換一個新的定時器。在前一個定時器代碼執(zhí)行完之前,不會向隊(duì)列插入新的定時器代碼,確保不會有任何確實(shí)的間隔。并且確保在下一次定時器代碼執(zhí)行之前,至少要等待指定的間隔,避免了連續(xù)的運(yùn)行。當(dāng)方法執(zhí)行完成定時器就立即停止(但是定時器還在,只不過沒用了).
缺點(diǎn):
(1)利用seTimeout實(shí)現(xiàn)的動畫在某些低端機(jī)上會出現(xiàn)卡頓、抖動的現(xiàn)象。
(2)settimeout的執(zhí)行時間并不是確定的。在js中, settimeout 任務(wù)被放進(jìn)了異步隊(duì)列中,只有當(dāng)主線程上的任務(wù)執(zhí)行完以后,才會去檢查該隊(duì)列里的任務(wù)是否需要開始執(zhí)行,因此 settimeout 的實(shí)際執(zhí)行時間一般要比其設(shè)定的時間晚一些。
(3)刷新頻率受屏幕分辨率和屏幕尺寸的影響,因此不同設(shè)備的屏幕刷新頻率可能會不同,而 settimeout只能設(shè)置一個固定的時間間隔,這個時間不一定和屏幕的刷新時間相同。
(4)settimeout的執(zhí)行只是在內(nèi)存中對圖像屬性進(jìn)行改變,這個變化必須要等到屏幕下次刷新時才會被更新到屏幕上。如果兩者的步調(diào)不一致,就可能會導(dǎo)致中間某一幀的操作被跨越過去,而直接更新下一幀的圖像。
3》requestAnimationFrame
缺點(diǎn): requestanimationframe 不管理回調(diào)函數(shù),即在回調(diào)被執(zhí)行前,多次調(diào)用帶有同一回調(diào)函數(shù)的 requestanimationframe,會導(dǎo)致回調(diào)在同一幀中執(zhí)行多次。
解決辦法: 對于這種高頻發(fā)事件,一般的解決方法是使用節(jié)流函數(shù)。但是在這里使用節(jié)流函數(shù)并不能完美解決問題。因?yàn)楣?jié)流函數(shù)是通過時間管理隊(duì)列的,完美的解決方案是通過 requestanimationframe 來管理隊(duì)列,其思路就是保證 requestanimationframe 的隊(duì)列里,同樣的回調(diào)函數(shù)只有一個。

4》與setTimeout和setInterval的區(qū)別
【1】執(zhí)行次數(shù):setInterval執(zhí)行多次,setTimeout、requestAnimationframe執(zhí)行一次
【2】性能:setTimeout會出現(xiàn)丟幀、卡頓現(xiàn)象,setInterval會出現(xiàn)調(diào)用丟失情況,requestAnimationframe不會出現(xiàn)這些問題,頁面未激活時不會執(zhí)行動畫,減少了大量cpu消耗
【3】兼容性問題:setInterval,setTimeout在IE瀏覽器中不支持參數(shù)傳遞,能夠在大多數(shù)瀏覽器中正常使用。而requestAnimationframe不兼容IE10以下.
5》requestAnimationFrame補(bǔ)充
除了上文提到的requestAnimationFrame的優(yōu)勢外,requestAnimationFrame還有以下兩個優(yōu)勢:
【1】CPU節(jié)能:使用setTimeout實(shí)現(xiàn)的動畫,當(dāng)頁面被隱藏或最小化時,setTimeout 仍然在后臺執(zhí)行動畫任務(wù),由于此時頁面處于不可見或不可用狀態(tài),刷新動畫是沒有意義的,完全是浪費(fèi)CPU資源。而requestAnimationFrame則完全不同,當(dāng)頁面處于未激活的狀態(tài)下,該頁面的屏幕刷新任務(wù)也會被系統(tǒng)暫停,因此跟著系統(tǒng)步伐走的requestAnimationFrame也會停止渲染,當(dāng)頁面被激活時,動畫就從上次停留的地方繼續(xù)執(zhí)行,有效節(jié)省了CPU開銷。
【2】函數(shù)節(jié)流:在高頻率事件(resize,scroll等)中,為了防止在一個刷新間隔內(nèi)發(fā)生多次函數(shù)執(zhí)行,使用requestAnimationFrame可保證每個刷新間隔內(nèi),函數(shù)只被執(zhí)行一次,這樣既能保證流暢性,也能更好的節(jié)省函數(shù)執(zhí)行的開銷。一個刷新間隔內(nèi)函數(shù)執(zhí)行多次是沒有意義的,因?yàn)轱@示器每16.7ms刷新一次,多次繪制并不會在屏幕上體現(xiàn)出來。
5.應(yīng)用場景
【1】監(jiān)聽 scroll 函數(shù) 頁面滾動事件(scroll)的監(jiān)聽函數(shù),就很適合用這個 api,推遲到下一次重新渲染。

【2】大量數(shù)據(jù)渲染 比如對十萬條數(shù)據(jù)進(jìn)行渲染,主要由以下幾種方法:
(1)使用定時器

(2)使用 requestAnimationFrame

【3】監(jiān)控卡頓方法 :每秒中計(jì)算一次網(wǎng)頁的 FPS(畫面每秒傳輸幀數(shù)),獲得一列數(shù)據(jù),然后分析。通俗地解釋就是,通過 requestAnimationFrame API 來定時執(zhí)行一些 JS 代碼,如果瀏覽器卡頓,無法很好地保證渲染的頻率,1s 中 frame 無法達(dá)到 60 幀,即可間接地反映瀏覽器的渲染幀率。

總結(jié)
到此這篇關(guān)于requestAnimationFrame請求動畫幀的文章就介紹到這了,更多相關(guān)requestAnimationFrame請求動畫幀內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript中null和undefined的區(qū)別詳解
null 是一個原始值,表示“無”或“空值”,它通常用于指示變量應(yīng)有的對象或值不存在,undefined 是一個原始值,表示“未定義”,本文給大家詳細(xì)介紹了JavaScript中null和undefined的區(qū)別,需要的朋友可以參考下2024-10-10
文字溢出實(shí)現(xiàn)溢出的部分再放入一個新生成的div中具體代碼
說文字溢出,如何實(shí)現(xiàn)溢出的文字放入一個新生成的div中,原理就是判斷是否能在div里放下,如果不能,則在應(yīng)該斷開的地方,差入到新的div中2013-05-05
一文詳解JavaScript中的相等運(yùn)算符與類型轉(zhuǎn)換
在?JavaScript?編程中,相等運(yùn)算符和類型轉(zhuǎn)換是理解語言行為的關(guān)鍵部分,雖然這些概念看似簡單,但它們的細(xì)節(jié)可能會導(dǎo)致意想不到的結(jié)果,本文將深入探討?==?和?===?運(yùn)算符的區(qū)別、對象比較、以及?JavaScript?中的顯式和隱式類型轉(zhuǎn)換,需要的朋友可以參考下2024-07-07
js表格排序?qū)嵗治觯ㄖС謎nt,float,date,string四種數(shù)據(jù)類型)
這篇文章主要介紹了js表格排序?qū)嵗治觯ㄖС謎nt,float,date,string四種數(shù)據(jù)類型),涉及javascript常用的升序、降序及數(shù)據(jù)類型轉(zhuǎn)換等相關(guān)技巧,需要的朋友可以參考下2015-05-05
DB.ASP 用Javascript寫ASP很靈活很好用很easy
DB.ASP 用Javascript寫ASP很靈活很好用很easy,喜歡用js寫asp的朋友可以參考下。2011-07-07
深入淺析JavaScript中prototype和proto的關(guān)系
prototype,每一個函數(shù)對象都有一個顯示的prototype屬性,而proto每個對象都有一個名為_proto_內(nèi)部隱藏屬性。本文給大家介紹JavaScript中prototype和proto的關(guān)系,需要的朋友參考下2015-11-11

