摘要:即在回調被執行前,多次調用帶有同一回調函數的,會導致回調在同一幀中執行多次。例子中的是由傳給回調函數的,表示回調隊列被觸發的時間。完美的解決方案是通過來管理隊列,其思路就是保證的隊列里,同樣的回調函數只有一個。
requestAnimationFrame 方法讓我們可以在下一幀開始時調用指定函數。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的回調函數里繪制動畫會有一個問題。是什么問題呢?要理解這個問題,我們先要了解 requestAnimationFrame 的一個知識點。
requestAnimationFrame 不管理回調函數這個知識點就是 requestAnimationFrame 不管理回調函數。這一點在 w3c 中明確說明了。
Also note that multiple calls to requestAnimationFrame with the same callback (before callbacks are invoked and the list is cleared) will result in multiple entries being in the list with that same callback, and thus will result in that callback being invoked more than once for the animation frame.
— w3c
即在回調被執行前,多次調用帶有同一回調函數的 requestAnimationFrame,會導致回調在同一幀中執行多次。我們可以通過一個簡單的例子模擬在同一幀內多次調用 requestAnimationFrame 的場景:
const animation = timestamp => console.log("animation called at", timestamp) window.requestAnimationFrame(animation) window.requestAnimationFrame(animation) // animation called at 320.7559999991645 // animation called at 320.7559999991645
我們用連續調用兩次 requestAnimationFrame 模擬在同一幀中調用兩次 requestAnimationFrame。
例子中的 timestamp 是由 requestAnimationFrame 傳給回調函數的,表示回調隊列被觸發的時間。由輸出可知,animation 函數在同一幀內被執行了兩次,即繪制了兩次動畫。然而在同一幀繪制兩次動畫很明顯是多余的,相當于畫了一幅畫,然后再在這幅畫上再畫上同樣的一幅畫。
問題那么什么場景下,requestAnimationFrame 會在一幀內被多次調用呢?熟悉事件的同學應該馬上能想到 mousemove, scroll 這類事件。
所以前面我們提到的問題就是:因為 requestAnimationFrame 不管理回調函數,在滾動、觸摸這類高觸發頻率的事件回調里,如果調用 requestAnimationFrame 然后繪制動畫,可能會造成多余的計算和繪制。例如:
window.addEventListener("scroll", e => { window.requestAnimationFrame(timestamp => { animation(timestamp) }) })
在上面代碼中,scroll 事件可能在一幀內多次觸發,所以 animation 函數可能會在一幀內重復繪制,造成不必要的計算和渲染。
解決方法對于這種高頻發事件,一般的解決方法是使用節流函數。但是在這里使用節流函數并不能完美解決問題。因為節流函數是通過時間管理隊列的,而 requestAnimationFrame 的觸發時間是不固定的,在高刷新頻率的顯示屏上時間會小于 16.67ms,頁面如果被推入后臺,時間可能大于 16.67ms。
完美的解決方案是通過 requestAnimationFrame 來管理隊列,其思路就是保證 requestAnimationFrame 的隊列里,同樣的回調函數只有一個。示意代碼如下:
const onScroll = e => { if (scheduledAnimationFrame) { return } scheduledAnimationFrame = true window.requestAnimationFrame(timestamp => { scheduledAnimationFrame = false animation(timestamp) }) } window.addEventListener("scroll", onScroll)
但是每次都要寫這么一堆代碼,也有點麻煩。所以我開源了 raf-plus 庫用于解決這個問題,有需要的的同學可以用用~
結論requestAnimationFrame 不管理回調函數隊列,而滾動、觸摸這類高觸發頻率事件的回調可能會在同一幀內觸發多次。所以正確使用 requestAnimationFrame 的姿勢是,在同一幀內可能調用多次 requestAnimationFrame 時,要管理回調函數,防止重復繪制動畫。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/106998.html
摘要:即在回調被執行前,多次調用帶有同一回調函數的,會導致回調在同一幀中執行多次。例子中的是由傳給回調函數的,表示回調隊列被觸發的時間。完美的解決方案是通過來管理隊列,其思路就是保證的隊列里,同樣的回調函數只有一個。 requestAnimationFrame 方法讓我們可以在下一幀開始時調用指定函數。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的...
摘要:即在回調被執行前,多次調用帶有同一回調函數的,會導致回調在同一幀中執行多次。例子中的是由傳給回調函數的,表示回調隊列被觸發的時間。完美的解決方案是通過來管理隊列,其思路就是保證的隊列里,同樣的回調函數只有一個。 requestAnimationFrame 方法讓我們可以在下一幀開始時調用指定函數。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的...
摘要:即在回調被執行前,多次調用帶有同一回調函數的,會導致回調在同一幀中執行多次。例子中的是由傳給回調函數的,表示回調隊列被觸發的時間。完美的解決方案是通過來管理隊列,其思路就是保證的隊列里,同樣的回調函數只有一個。 requestAnimationFrame 方法讓我們可以在下一幀開始時調用指定函數。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的...
摘要:即在回調被執行前,多次調用帶有同一回調函數的,會導致回調在同一幀中執行多次。例子中的是由傳給回調函數的,表示回調隊列被觸發的時間。完美的解決方案是通過來管理隊列,其思路就是保證的隊列里,同樣的回調函數只有一個。 requestAnimationFrame 方法讓我們可以在下一幀開始時調用指定函數。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的...
摘要:即在回調被執行前,多次調用帶有同一回調函數的,會導致回調在同一幀中執行多次。例子中的是由傳給回調函數的,表示回調隊列被觸發的時間。完美的解決方案是通過來管理隊列,其思路就是保證的隊列里,同樣的回調函數只有一個。 requestAnimationFrame 方法讓我們可以在下一幀開始時調用指定函數。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的...
閱讀 1239·2021-11-11 16:55
閱讀 1537·2021-10-08 10:16
閱讀 1188·2021-09-26 10:20
閱讀 3569·2021-09-01 10:47
閱讀 2451·2019-08-30 15:52
閱讀 2682·2019-08-30 13:18
閱讀 3194·2019-08-30 13:15
閱讀 1115·2019-08-30 10:55