摘要:方法用于取消先前安排的一個(gè)動(dòng)畫(huà)幀更新的請(qǐng)求。當(dāng)調(diào)用時(shí),瀏覽器會(huì)設(shè)置該指向的回調(diào)函數(shù)的為。無(wú)論該回調(diào)函數(shù)是否在動(dòng)畫(huà)幀請(qǐng)求回調(diào)函數(shù)列表中,它的都會(huì)被設(shè)置為。
引入
計(jì)時(shí)器一直是JavaScript動(dòng)畫(huà)的核心技術(shù)。而編寫(xiě)動(dòng)畫(huà)循環(huán)的關(guān)鍵是要知道延遲時(shí)間多長(zhǎng)合適。一方面,循環(huán)間隔必須足夠短,這樣才能讓不同的動(dòng)畫(huà)效果顯得平滑流暢;另一方面,循環(huán)間隔還要足夠長(zhǎng),這樣才能確保瀏覽器有能力渲染產(chǎn)生的變化。
如何保證流暢呢?登登登登....該requestAnimationFrame登場(chǎng)了~~
16.7ms的由來(lái)大多數(shù)電腦顯示器的刷新頻率是60Hz,大概相當(dāng)于每秒鐘重繪60次。大多數(shù)瀏覽器都會(huì)對(duì)重繪操作加以限制,不超過(guò)顯示器的重繪頻率,因?yàn)榧词钩^(guò)那個(gè)頻率用戶體驗(yàn)也不會(huì)有提升。因此,最平滑動(dòng)畫(huà)的最佳循環(huán)間隔是1000ms/60,約等于16.7ms。
settimeout->OUT同樣的,顯示器16.7ms刷新間隔之前發(fā)生了其他繪制請(qǐng)求(setTimeout),導(dǎo)致所有第三幀丟失,繼而導(dǎo)致動(dòng)畫(huà)斷續(xù)顯示(堵車(chē)的感覺(jué)),這就是過(guò)度繪制帶來(lái)的問(wèn)題。不僅如此,這種計(jì)時(shí)器頻率的降低也會(huì)對(duì)電池使用壽命造成負(fù)面影響,并會(huì)降低其他應(yīng)用的性能。
這也是為何setTimeout的定時(shí)器值推薦最小使用16.7ms的原因(16.7 = 1000 / 60, 即每秒60幀)。
但......OUT requestAnimationFrame登場(chǎng)1、即使向其傳遞毫秒為單位的參數(shù),它們也不能達(dá)到ms的準(zhǔn)確性。這是因?yàn)閖avascript是單線程的,可能會(huì)發(fā)生阻塞。
2、沒(méi)有對(duì)調(diào)用動(dòng)畫(huà)的循環(huán)機(jī)制進(jìn)行優(yōu)化。
3、沒(méi)有考慮到繪制動(dòng)畫(huà)的最佳時(shí)機(jī),只是一味地以某個(gè)大致的事件間隔來(lái)調(diào)用循環(huán)。
requestAnimationFrame不需要使用者指定循環(huán)間隔時(shí)間,瀏覽器會(huì)基于當(dāng)前頁(yè)面是否可見(jiàn)、CPU的負(fù)荷情況等來(lái)自行決定最佳的幀速率,跟著瀏覽器的繪制走,如果瀏覽設(shè)備繪制間隔是16.7ms,那我就這個(gè)間隔繪制;如果瀏覽設(shè)備繪制間隔是10ms, 我就10ms繪制。
這樣自然就合理地使用CPU,不會(huì)存在過(guò)度繪制的問(wèn)題,動(dòng)畫(huà)不會(huì)掉幀,自然流暢的說(shuō)~~
內(nèi)部是這么運(yùn)作的:
瀏覽器(如頁(yè)面)每次重繪,就會(huì)通知我(requestAnimationFrame):嗨,我要重繪了,你可以跟我一起重繪哦!
這是資源非常高效的一種利用方式。怎么講呢?
總結(jié):1.就算很多元素需要重繪,瀏覽器只要通知一次就可以了。而setTimeout貌似是多個(gè)獨(dú)立繪制。
2.頁(yè)面最小化了,或者被Tab切換關(guān)燈了。頁(yè)面是不會(huì)重繪的,自然,requestAnimationFrame也不會(huì)洗澡的(沒(méi)通知啊)。頁(yè)面繪制全部停止,資源高效利用。
setTimeout和setInterval都不精確。它們的內(nèi)在運(yùn)行機(jī)制決定了時(shí)間間隔參數(shù)實(shí)際上只是指定了把動(dòng)畫(huà)代碼添加到瀏覽器UI線程隊(duì)列中以等待執(zhí)行的時(shí)間。如果隊(duì)列前面已經(jīng)加入了其他任務(wù),那動(dòng)畫(huà)代碼就要等前面的任務(wù)完成后再執(zhí)行。
requestAnimationFrame采用系統(tǒng)時(shí)間間隔,保持最佳繪制效率,不會(huì)因?yàn)殚g隔時(shí)間過(guò)短,造成過(guò)度繪制,增加開(kāi)銷(xiāo);也不會(huì)因?yàn)殚g隔時(shí)間太長(zhǎng),使用動(dòng)畫(huà)卡頓不流暢,讓各種網(wǎng)頁(yè)動(dòng)畫(huà)效果能夠有一個(gè)統(tǒng)一的刷新機(jī)制,從而節(jié)省系統(tǒng)資源,提高系統(tǒng)性能,改善視覺(jué)效果。
requestAnimationFrame會(huì)把每一幀中的所有DOM操作集中起來(lái),在一次重繪或回流中就完成,并且重繪或回流的時(shí)間間隔緊緊跟隨瀏覽器的刷新頻率
在隱藏或不可見(jiàn)的元素中,requestAnimationFrame將不會(huì)進(jìn)行重繪或回流,這當(dāng)然就意味著更少的CPU、GPU和內(nèi)存使用量
requestAnimationFrame是由瀏覽器專(zhuān)門(mén)為動(dòng)畫(huà)提供的API,在運(yùn)行時(shí)瀏覽器會(huì)自動(dòng)優(yōu)化方法的調(diào)用,并且如果頁(yè)面不是激活狀態(tài)下的話,動(dòng)畫(huà)會(huì)自動(dòng)暫停,有效節(jié)省了CPU開(kāi)銷(xiāo)
名詞解釋動(dòng)畫(huà)幀請(qǐng)求回調(diào)函數(shù)列表 |
每個(gè)Document都有一個(gè)動(dòng)畫(huà)幀請(qǐng)求回調(diào)函數(shù)列表,該列表可以看成是由< handle, callback>元組組成的集合。其中handle是一個(gè)整數(shù),唯一地標(biāo)識(shí)了元組在列表中的位置;callback是一個(gè)無(wú)返回值的、形參為一個(gè)時(shí)間值的函數(shù)(該時(shí)間值為由瀏覽器傳入的從1970年1月1日到當(dāng)前所經(jīng)過(guò)的毫秒數(shù))。 剛開(kāi)始該列表為空。 |
Document |
Dom模型中定義的Document節(jié)點(diǎn) |
Active document |
瀏覽器上下文browsingContext中的Document被指定為active document |
browsingContext |
即瀏覽器上下文。 瀏覽器上下文是呈現(xiàn)document對(duì)象給用戶的環(huán)境。 瀏覽器中的1個(gè)tab或一個(gè)窗口包含一個(gè)頂級(jí)瀏覽器上下文,如果該頁(yè)面有iframe,則iframe中也會(huì)有自己的瀏覽器上下文,稱為嵌套的瀏覽器上下文。 |
頁(yè)面可見(jiàn) |
當(dāng)頁(yè)面被最小化或者被切換成后臺(tái)標(biāo)簽頁(yè)時(shí),頁(yè)面為不可見(jiàn),瀏覽器會(huì)觸發(fā)一個(gè) visibilitychange事件,并設(shè)置document.hidden屬性為true;切換到顯示狀態(tài)時(shí),頁(yè)面為可見(jiàn),也同樣觸發(fā)一個(gè) visibilitychange事件,設(shè)置document.hidden屬性為false |
隊(duì)列 |
瀏覽器讓一個(gè)單線程共用于執(zhí)行javascrip和更新用戶界面。這個(gè)線程通常被稱為“瀏覽器UI線程”。 瀏覽器UI線程的工作基于一個(gè)簡(jiǎn)單的隊(duì)列系統(tǒng),任務(wù)會(huì)被保存到隊(duì)列中直到進(jìn)程空閑。一旦空閑,隊(duì)列中的下一個(gè)任務(wù)就被重新提取出來(lái)并運(yùn)行。這些任務(wù)要么是運(yùn)行javascript代碼,要么執(zhí)行UI更新,包括重繪和重排。 |
Window對(duì)象定義了以下兩個(gè)接口:
partial interface Window { long requestAnimationFrame(FrameRequestCallback callback); void cancelAnimationFrame(long handle); };requestAnimationFrame
1.requestAnimationFrame方法用于通知瀏覽器重采樣動(dòng)畫(huà)。
當(dāng)requestAnimationFrame(callback)被調(diào)用時(shí)不會(huì)執(zhí)行callback,而是會(huì)將元組< handle,callback>插入到動(dòng)畫(huà)幀請(qǐng)求回調(diào)函數(shù)列表末尾(其中元組的callback就是傳入requestAnimationFrame的回調(diào)函數(shù)),并且返回handle值,該值為瀏覽器定義的、大于0的整數(shù),唯一標(biāo)識(shí)了該回調(diào)函數(shù)在列表中位置。
2.每個(gè)回調(diào)函數(shù)都有一個(gè)布爾標(biāo)識(shí)cancelled,該標(biāo)識(shí)初始值為false,并且對(duì)外不可見(jiàn)。
3.在后面的“處理模型” 中我們會(huì)看到,瀏覽器在執(zhí)行“采樣所有動(dòng)畫(huà)”的任務(wù)時(shí)會(huì)遍歷動(dòng)畫(huà)幀請(qǐng)求回調(diào)函數(shù)列表,判斷每個(gè)元組的callback的cancelled,如果為false,則執(zhí)行callback。
1、cancelAnimationFrame 方法用于取消先前安排的一個(gè)動(dòng)畫(huà)幀更新的請(qǐng)求。
2、當(dāng)調(diào)用cancelAnimationFrame(handle)時(shí),瀏覽器會(huì)設(shè)置該handle指向的回調(diào)函數(shù)的cancelled為true。
無(wú)論該回調(diào)函數(shù)是否在動(dòng)畫(huà)幀請(qǐng)求回調(diào)函數(shù)列表中,它的cancelled都會(huì)被設(shè)置為true。
3.如果該handle沒(méi)有指向任何回調(diào)函數(shù),則調(diào)用cancelAnimationFrame 不會(huì)發(fā)生任何事情。
4.注意:在requestAnimationFrame的callback內(nèi)部執(zhí)行cancelAnimationFrame不能取消動(dòng)畫(huà)
當(dāng)頁(yè)面可見(jiàn)并且動(dòng)畫(huà)幀請(qǐng)求回調(diào)函數(shù)列表不為空時(shí),瀏覽器會(huì)定期地加入一個(gè)“采樣所有動(dòng)畫(huà)”的任務(wù)到UI線程的隊(duì)列中。
使用requestAnimationFrame的用法與setTimeout很相似,只是不需要設(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í)行。
requestID = requestAnimationFrame(callback);完美兼容
如果想要簡(jiǎn)單的兼容,可以這樣子:
window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function( callback ){ window.setTimeout(callback, 1000 / 60); }; })();
但是呢,并不是所有設(shè)備的繪制時(shí)間間隔是1000/60 ms, 以及上面并木有cancel相關(guān)方法,所以,就有下面這份更全面的兼容方法:
(function() { var lastTime = 0; var vendors = ["webkit", "moz"]; for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x] + "RequestAnimationFrame"]; window.cancelAnimationFrame = window[vendors[x] + "CancelAnimationFrame"] || // Webkit中此取消方法的名字變了 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 = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; } if (!window.cancelAnimationFrame) { window.cancelAnimationFrame = function(id) { clearTimeout(id); }; } }());
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/90021.html
摘要:方法用于取消先前安排的一個(gè)動(dòng)畫(huà)幀更新的請(qǐng)求。當(dāng)調(diào)用時(shí),瀏覽器會(huì)設(shè)置該指向的回調(diào)函數(shù)的為。無(wú)論該回調(diào)函數(shù)是否在動(dòng)畫(huà)幀請(qǐng)求回調(diào)函數(shù)列表中,它的都會(huì)被設(shè)置為。 引入 計(jì)時(shí)器一直是JavaScript動(dòng)畫(huà)的核心技術(shù)。而編寫(xiě)動(dòng)畫(huà)循環(huán)的關(guān)鍵是要知道延遲時(shí)間多長(zhǎng)合適。一方面,循環(huán)間隔必須足夠短,這樣才能讓不同的動(dòng)畫(huà)效果顯得平滑流暢;另一方面,循環(huán)間隔還要足夠長(zhǎng),這樣才能確保瀏覽器有能力渲染產(chǎn)生的變化...
摘要:方法用于取消先前安排的一個(gè)動(dòng)畫(huà)幀更新的請(qǐng)求。當(dāng)調(diào)用時(shí),瀏覽器會(huì)設(shè)置該指向的回調(diào)函數(shù)的為。無(wú)論該回調(diào)函數(shù)是否在動(dòng)畫(huà)幀請(qǐng)求回調(diào)函數(shù)列表中,它的都會(huì)被設(shè)置為。 引入 計(jì)時(shí)器一直是JavaScript動(dòng)畫(huà)的核心技術(shù)。而編寫(xiě)動(dòng)畫(huà)循環(huán)的關(guān)鍵是要知道延遲時(shí)間多長(zhǎng)合適。一方面,循環(huán)間隔必須足夠短,這樣才能讓不同的動(dòng)畫(huà)效果顯得平滑流暢;另一方面,循環(huán)間隔還要足夠長(zhǎng),這樣才能確保瀏覽器有能力渲染產(chǎn)生的變化...
摘要:最近一直在忙公司炒股大賽的頁(yè)面,終于在昨天把他給上線了。剛開(kāi)始學(xué)習(xí)的時(shí)候,真心覺(jué)得無(wú)縫滾動(dòng)是一個(gè)神奇的功能。原理假如需要無(wú)縫滾動(dòng)的個(gè)元素是一個(gè)中的個(gè)。我們將控制在容器中滾動(dòng)。這樣無(wú)縫滾動(dòng)就已經(jīng)實(shí)現(xiàn)了。 最近一直在忙公司炒股大賽的頁(yè)面,終于在昨天把他給上線了。一個(gè)看似簡(jiǎn)單的頁(yè)面,做起來(lái)才知道其中的艱辛,暗藏深坑。由于直接使用jquery來(lái)寫(xiě)頁(yè)面邏輯,因此要比想象中復(fù)雜很多。無(wú)論是從布局,...
摘要:創(chuàng)建場(chǎng)景標(biāo)簽本節(jié)目標(biāo)是為做簡(jiǎn)介。我們從使用旋轉(zhuǎn)立方體來(lái)搭建場(chǎng)景開(kāi)始。我們現(xiàn)在創(chuàng)建了場(chǎng)景,攝像機(jī)和渲染器。我們需要來(lái)創(chuàng)建立方體。這會(huì)導(dǎo)致攝像機(jī)和立方體內(nèi)部重疊。這會(huì)創(chuàng)建一個(gè)讓渲染器每秒繪制一幀的循環(huán)。結(jié)果恭喜你現(xiàn)在創(chuàng)建好了第一個(gè)應(yīng)用。 1.創(chuàng)建場(chǎng)景 標(biāo)簽: three.js 本節(jié)目標(biāo)是為 three.js 做簡(jiǎn)介。我們從使用旋轉(zhuǎn)立方體來(lái)搭建場(chǎng)景開(kāi)始。如果遇到困難需要幫助,頁(yè)面底部有可參考...
摘要:注以下所有代碼托管到動(dòng)畫(huà)的數(shù)理分析有了前面的基礎(chǔ)知識(shí),現(xiàn)在我們就會(huì)想如果我們能夠在每秒幀,內(nèi)渲染張圖像,并且每一張圖像的內(nèi)容發(fā)生微調(diào),那么在秒鐘整個(gè)畫(huà)面就會(huì)產(chǎn)生動(dòng)畫(huà)效果了。 什么是動(dòng)畫(huà)? 就像思考哲學(xué)問(wèn)題無(wú)法回避思維和存在的關(guān)系一樣,制作動(dòng)畫(huà)同樣無(wú)法逃避的問(wèn)題是動(dòng)畫(huà)的原理是什么?這里提一句題外話,任何原理的東西通常難以讓你短期拾掇成果,但在隱約的未來(lái)會(huì)起到難以置信的效果,不信就看接下來(lái)...
閱讀 2025·2023-04-26 00:16
閱讀 3475·2021-11-15 11:38
閱讀 3168·2019-08-30 12:50
閱讀 3178·2019-08-29 13:59
閱讀 750·2019-08-29 13:54
閱讀 2496·2019-08-29 13:42
閱讀 3305·2019-08-26 11:45
閱讀 2187·2019-08-26 11:36