requestAnimationFrame()詳解
關於requestAnimationFrame()基本用法和概念可以參閱requestAnimationFrame()用法一章節。
下面再從更為底層的層面來對此方法進行一下介紹,感興趣的朋友可以做一下參考。
回撥函式列表:
每一個document物件都有一個動畫幀請求回撥函式列表;該列表中儲存著由<handle, callback>組成的集合。
(1).callback:它就是傳遞給requestAnimationFrame()方法的回撥函式;此函式沒有返回值,引數(可以省略)是一個時間值(該值由瀏覽器傳入,從1970年1月1日到當前所經過的毫秒數)。
(2).handle:是一個整數,唯一地標識了元組在列表中的位置,cancelAnimationFrame()可以通過它來停止動畫。
瀏覽器UI執行緒:
此執行緒用於執行javascript或者介面的更新。
基於一個簡單的佇列系統,任務會被儲存到佇列中直到程式空閒。
一旦空閒,佇列中的下一個任務就被重新提取出來並執行。
這些任務要麼是執行javascript程式碼,要麼執行UI更新,包括重繪和重排。
頁面是否啟用:
當頁面被最小化或者被切換成非當前選項卡時,頁面為不可見或者說沒有啟用,瀏覽器會觸發visibilitychange事件,並設定document.hidden屬性為true;切換到顯示狀態時,頁面為可見,也同樣觸發一個 visibilitychange事件,設定document.hidden屬性為false。
requestAnimationFrame:
此方法可以將回撥函式追加到動畫幀請求回撥函式列表的末尾。
當執行requestAnimationFrame(callback)時候,不會立刻呼叫callback函式,只是將其放入佇列。
每個回撥函式都有一個布林標識cancelled,該標識初始值為false,並且對外不可見;當瀏覽器再執行列表中的回撥函式的時候,判斷每個元組的callback的cancelled,如果為false,則執行callback。
cancelAnimationFrame:
方法能夠取消一個動畫幀更新的請求。
當呼叫cancelAnimationFrame(handle)時,瀏覽器會設定該handle指向的回撥函式的cancelled為true。
無論該回撥函式是否在動畫幀請求回撥函式列表中,它的cancelled都會被設定為true。
如果該handle沒有指向任何回撥函式,則呼叫cancelAnimationFrame 不會發生任何事情。
處理模型:
當頁面可見並且動畫幀請求回撥函式列表不為空時,瀏覽器會定期獎這些回撥函式加入到UI執行緒的佇列中。
此處使用虛擬碼來說明“取樣所有動畫”任務的執行步驟:
[JavaScript] 純文字檢視 複製程式碼var list = {}; var browsingContexts = 瀏覽器頂級上下文及其下屬的瀏覽器上下文; for (var browsingContext in browsingContexts) { //var time = 從1970年1月1日到當前所經過的毫秒數; var time = DOMHighResTimeStamp var d = browsingContext的active document; //即當前瀏覽器上下文中的Document節點 //如果該active document可見 if (d.hidden !== true) { //拷貝active document的動畫幀請求回撥函式列表到list中,並清空該列表 var doclist = d的動畫幀請求回撥函式列表 doclist.appendTo(list); clear(doclist); } //遍歷動畫幀請求回撥函式列表的元組中的回撥函式 for (var callback in list) { if (callback.cancelled !== true) { try { //每個browsingContext都有一個對應WindowProxy,WindowProxy物件會將callback指向active document關聯的window。 //傳入時間值time callback.call(window, time); } //忽略異常 catch (e) {} } } }
看一段程式碼例項:
[JavaScript] 純文字檢視 複製程式碼var id = null; function func(time) { console.log("螞蟻部落"); window.cancelAnimationFrame(id); id = window.requestAnimationFrame(func); } func();
我們的目的是是函式只執行一次,但是結果卻是會無限迴圈下去,下面做一下分析:
(1).func()呼叫之後,當執行到window.cancelAnimationFrame(id),id是null,所以它沒有取消任何動畫請求幀回撥函式的執行。
(2).id = window.requestAnimationFrame(func),又將一個新的回撥函式追加到佇列。
(3).所以func又將會被加入UI執行緒的佇列中,func()又將被執行;雖然window.cancelAnimationFrame(id)的引數這次不會null,但是與此id對應的回撥函式已經執行了,程式碼修改如下:
[JavaScript] 純文字檢視 複製程式碼var id = null; function func(time) { console.log("螞蟻部落"); id = window.requestAnimationFrame(func); window.cancelAnimationFrame(id); } func();
只要將程式碼的順序對調一下即可。
相關文章
- requestAnimationFrame()requestAnimationFrame
- requestAnimationFrame用法requestAnimationFrame
- requestAnimationFrame()用法requestAnimationFrame
- 有關requestAnimationFramerequestAnimationFrame
- 淺析 requestAnimationFramerequestAnimationFrame
- requestAnimationFrame 知多少?requestAnimationFrame
- 【譯】前端requestAnimationFrame概述前端requestAnimationFrame
- 深入理解 requestAnimationFramerequestAnimationFrame
- HTML5動畫API—— requestAnimationFrameHTML動畫APIrequestAnimationFrame
- requestAnimationFrame 執行機制探索requestAnimationFrame
- requestAnimationFrame中完成想要的渲染requestAnimationFrame
- 你需要知道的requestAnimationFramerequestAnimationFrame
- javascript requestAnimationFrame vs. setTimeoutJavaScriptrequestAnimationFrame
- requestAnimationFrame()動畫例項程式碼requestAnimationFrame動畫
- 定時器(setInterval、setTimeout 和requestAnimationFrame)定時器requestAnimationFrame
- 你知道的requestAnimationFrame【從0到0.1】requestAnimationFrame
- 用requestAnimationFrame優化你的javascript動畫requestAnimationFrame優化JavaScript動畫
- JS動畫三劍客——setTimeout、setInterval、requestAnimationFrameJS動畫requestAnimationFrame
- 深入理解HTML5定時器requestAnimationFrameHTML定時器requestAnimationFrame
- requestAnimationFrame實現一幀的函式節流requestAnimationFrame函式
- js利用H5的requestAnimationFrame()API實現動畫效果JSH5requestAnimationFrameAPI動畫
- http協議/cookie詳解/session詳解HTTP協議CookieSession
- Lombok 註解詳解Lombok
- Java註解詳解Java
- Java 註解詳解Java
- Java註解最全詳解(超級詳細)Java
- HiveQL詳解Hive
- 詳解Inode
- Vuex詳解Vue
- PWA詳解
- 詳解CountDownLatchCountDownLatch
- DiffUtil詳解
- iptables詳解
- TCP詳解TCP
- CDN詳解
- Typescript詳解TypeScript
- Mybatis詳解MyBatis
- Synchronized詳解synchronized