<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
很長時間以來,計時器和定時執行都是 JavaScript 動畫最先進的工具。雖然 CSS 過渡和動畫方便了開發者實現某些動畫,但 JavaScript 動畫領域多年來進展甚微。requestAnimationFrame() 方法應運而生,這個方法會告訴瀏覽器要執行動畫了,於是瀏覽器可以通過最優方式確定重繪的時序。
以前,在 JavaScript 中建立動畫基本上就是使用 setInterval()
來控制動畫的執行:
(function () { function updateAnimations() { doAnimation1(); doAnimation2(); // ... } setInterval(updateAnimations, 100); })();
這種定時動畫的問題在於,無法準確知曉迴圈之間的延時。
無論是 setInterval()
還是 setTimeout()
,都是不能保證時間精度的。作為第二個引數的延時只能保證何時會把程式碼新增到瀏覽器的任務佇列,並不能保證新增到佇列就會立即執行。如果佇列前面還有其他任務,那麼就要等這些任務執行完再執行。
簡單來講,這裡的毫秒延時不是指何時這些程式碼會執行,而是指到時候會把回撥新增到任務佇列。如果新增到佇列後,主執行緒還被其他任務佔用,那麼回撥就不會立即執行。
知道何時繪製下一幀是創造平滑動畫的關鍵,所以 setInterval()
和 setTimeout()
的不精確是個大問題。
瀏覽器自身計時器的精度讓這個問題雪上加霜。瀏覽器計時器的精度不足毫秒,最厲害的 Chrome 計時器精度為 4ms。更麻煩的是,瀏覽器又開始對切換到後臺或不活躍的分頁中的計時器執行限流,因此即使將時間間隔設為最優,也免不了只能得到近似的結果。
一般計算機顯示器的螢幕重新整理率都是 60HZ,基本上意味著每秒需要重繪 60 次。大多數瀏覽器會限制重繪頻率,使其不超過螢幕的重新整理率,因為超過螢幕重新整理率使用者也感知不到。
所以,實現平滑動畫最佳的重繪時間間隔為 1000ms/60,大約 17 ms。以這個速度重繪可以實現最平滑的動畫,因為這已經是瀏覽器的極限了。
requestAnimationFrame()
這個方法可以通知瀏覽器某些 JavaScript 程式碼要執行動畫了,這樣瀏覽器就可以在執行某些程式碼後進行適當的優化。
requestAnimationFrame()
這個方法接收一個引數,該引數是一個要在重繪螢幕前呼叫的函數。這個函數就是修改 DOM 樣式以反映下一次重繪有什麼變化的地方。為了實現動畫迴圈,可以把多個 requestAnimationFrame()
呼叫串聯起來,就像以前使用 setTimeout()
一樣:
function updateProgress() { var div = document.getElementById("status"); div.style.width = parseInt(div.style.width, 10) + 5 + "%"; if (div.style.left != "100%") { requestAnimationFrame(updateProgress); } } requestAnimationFrame(updateProgress);
因為 requestAnimationFrame()
只會呼叫一次傳入的函數,所以每次更新使用者介面時需要再手動呼叫它一次。同時,也需要控制動畫何時停止。結果就會得到非常平滑的動畫。
requestAnimationFrame()
已經解決了瀏覽器不知道 JavaScript 動畫何時開始的問題,以及最佳間隔時間是多少的問題。但是,如果我們想知道自己的程式碼實際的執行時間呢?同樣有解決方案。
傳給 requestAnimationFrame()
的函數實際上可以接收一個引數,該參數列示下次重繪的時間。這一點非常重要:requestAnimationFrame()
實際上把重繪任務安排在了未來一個已知的時間點上,而且通過這個引數告訴了開發者,那麼基於這個引數,就可以更好地決定如何調優動畫了:
function foo(t) { console.log(t); requestAnimationFrame(foo); } requestAnimationFrame(foo);
const requestID = window.requestAnimationFrame((t) => { console.log(t); }); window.cancelAnimationFrame(requestID);
支援這個方法的瀏覽器實際上會暴露出作為勾點的回撥佇列。所謂勾點,就是瀏覽器在執行下一次重繪之前的一個點。這個回撥佇列是一個可修改的函數列表,包含應該在重繪之前呼叫的函數。每次呼叫 requestAnimationFrame()
都會在佇列上推入一個回撥函數,佇列的長度沒有限制。
這個回撥佇列的行為不一定跟動畫有關。通過 requestAnimationFrame()
遞迴地向佇列中加入回撥函數,可以保證每次重繪最多隻呼叫一次回撥函數,這是一個非常好的節流工具。在頻繁執行影響頁面外觀的程式碼時(比如捲動事件監聽器),可以利用這個回撥佇列進行節流。
先看一個原生實現,其中的捲動事件監聽器每次觸發都會呼叫名為 expensiveOperation()
(耗時操作) 的函數。當向下捲動網頁時,這個事件很快就會被觸發並執行成百上千次:
function expensiveOperation() { console.log("Invoked at", Date.now()); } window.addEventListener("scroll", () => { expensiveOperation(); });
如果想把事件處理程式的呼叫限制在每次重繪之前,那麼就可以把它封裝到 requestAnimationFrame()
呼叫中:
function expensiveOperation() { console.log("Invoked at", Date.now()); } window.addEventListener("scroll", () => { window.requestAnimationFrame(expensiveOperation); });
這樣會把所有回撥的執行集中在重繪勾點,但不會過濾掉每次重繪的多餘呼叫。我們可以定義一個標誌變數,在回撥中設定其狀態,就能將多餘的呼叫遮蔽:
let enqueued = false; function expensiveOperation() { console.log("Invoked at", Date.now()); enqueued = false; } window.addEventListener("scroll", () => { if (!enqueued) { enqueued = true; window.requestAnimationFrame(expensiveOperation); } });
因為重繪是非常頻繁的操作,所以這算不上是真正的節流。更好的方法是配合使用一個計時器來限制操作執行的頻率。這樣,計時器可以限制實際的操作執行間隔,而 requestAnimationFrame()
控制在瀏覽器的哪個渲染週期中執行:
let enabled = true; function expensiveOperation() { console.log("Invoked at", Date.now()); } window.addEventListener("scroll", () => { if (enabled) { enqueued = false; window.requestAnimationFrame(expensiveOperation); window.setTimeout(() => (enabled = true), 50); } });
上面的例子將回撥限制為大約 50ms 執行一次。
以上就是requestAnimationFrame定時動畫螢幕重新整理率節流範例淺析的詳細內容,更多關於requestAnimationFrame重新整理節流的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45