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