摘要:即在回調(diào)被執(zhí)行前,多次調(diào)用帶有同一回調(diào)函數(shù)的,會(huì)導(dǎo)致回調(diào)在同一幀中執(zhí)行多次。例子中的是由傳給回調(diào)函數(shù)的,表示回調(diào)隊(duì)列被觸發(fā)的時(shí)間。完美的解決方案是通過(guò)來(lái)管理隊(duì)列,其思路就是保證的隊(duì)列里,同樣的回調(diào)函數(shù)只有一個(gè)。
requestAnimationFrame 方法讓我們可以在下一幀開始時(shí)調(diào)用指定函數(shù)。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的回調(diào)函數(shù)里繪制動(dòng)畫會(huì)有一個(gè)問(wèn)題。是什么問(wèn)題呢?要理解這個(gè)問(wèn)題,我們先要了解 requestAnimationFrame 的一個(gè)知識(shí)點(diǎn)。
requestAnimationFrame 不管理回調(diào)函數(shù)這個(gè)知識(shí)點(diǎn)就是 requestAnimationFrame 不管理回調(diào)函數(shù)。這一點(diǎn)在 w3c 中明確說(shuō)明了。
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
即在回調(diào)被執(zhí)行前,多次調(diào)用帶有同一回調(diào)函數(shù)的 requestAnimationFrame,會(huì)導(dǎo)致回調(diào)在同一幀中執(zhí)行多次。我們可以通過(guò)一個(gè)簡(jiǎn)單的例子模擬在同一幀內(nèi)多次調(diào)用 requestAnimationFrame 的場(chǎng)景:
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
我們用連續(xù)調(diào)用兩次 requestAnimationFrame 模擬在同一幀中調(diào)用兩次 requestAnimationFrame。
例子中的 timestamp 是由 requestAnimationFrame 傳給回調(diào)函數(shù)的,表示回調(diào)隊(duì)列被觸發(fā)的時(shí)間。由輸出可知,animation 函數(shù)在同一幀內(nèi)被執(zhí)行了兩次,即繪制了兩次動(dòng)畫。然而在同一幀繪制兩次動(dòng)畫很明顯是多余的,相當(dāng)于畫了一幅畫,然后再在這幅畫上再畫上同樣的一幅畫。
問(wèn)題那么什么場(chǎng)景下,requestAnimationFrame 會(huì)在一幀內(nèi)被多次調(diào)用呢?熟悉事件的同學(xué)應(yīng)該馬上能想到 mousemove, scroll 這類事件。
所以前面我們提到的問(wèn)題就是:因?yàn)?requestAnimationFrame 不管理回調(diào)函數(shù),在滾動(dòng)、觸摸這類高觸發(fā)頻率的事件回調(diào)里,如果調(diào)用 requestAnimationFrame 然后繪制動(dòng)畫,可能會(huì)造成多余的計(jì)算和繪制。例如:
window.addEventListener("scroll", e => { window.requestAnimationFrame(timestamp => { animation(timestamp) }) })
在上面代碼中,scroll 事件可能在一幀內(nèi)多次觸發(fā),所以 animation 函數(shù)可能會(huì)在一幀內(nèi)重復(fù)繪制,造成不必要的計(jì)算和渲染。
解決方法對(duì)于這種高頻發(fā)事件,一般的解決方法是使用節(jié)流函數(shù)。但是在這里使用節(jié)流函數(shù)并不能完美解決問(wèn)題。因?yàn)楣?jié)流函數(shù)是通過(guò)時(shí)間管理隊(duì)列的,而 requestAnimationFrame 的觸發(fā)時(shí)間是不固定的,在高刷新頻率的顯示屏上時(shí)間會(huì)小于 16.67ms,頁(yè)面如果被推入后臺(tái),時(shí)間可能大于 16.67ms。
完美的解決方案是通過(guò) requestAnimationFrame 來(lái)管理隊(duì)列,其思路就是保證 requestAnimationFrame 的隊(duì)列里,同樣的回調(diào)函數(shù)只有一個(gè)。示意代碼如下:
const onScroll = e => { if (scheduledAnimationFrame) { return } scheduledAnimationFrame = true window.requestAnimationFrame(timestamp => { scheduledAnimationFrame = false animation(timestamp) }) } window.addEventListener("scroll", onScroll)
但是每次都要寫這么一堆代碼,也有點(diǎn)麻煩。所以我開源了 raf-plus 庫(kù)用于解決這個(gè)問(wèn)題,有需要的的同學(xué)可以用用~
結(jié)論requestAnimationFrame 不管理回調(diào)函數(shù)隊(duì)列,而滾動(dòng)、觸摸這類高觸發(fā)頻率事件的回調(diào)可能會(huì)在同一幀內(nèi)觸發(fā)多次。所以正確使用 requestAnimationFrame 的姿勢(shì)是,在同一幀內(nèi)可能調(diào)用多次 requestAnimationFrame 時(shí),要管理回調(diào)函數(shù),防止重復(fù)繪制動(dòng)畫。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/87141.html
摘要:即在回調(diào)被執(zhí)行前,多次調(diào)用帶有同一回調(diào)函數(shù)的,會(huì)導(dǎo)致回調(diào)在同一幀中執(zhí)行多次。例子中的是由傳給回調(diào)函數(shù)的,表示回調(diào)隊(duì)列被觸發(fā)的時(shí)間。完美的解決方案是通過(guò)來(lái)管理隊(duì)列,其思路就是保證的隊(duì)列里,同樣的回調(diào)函數(shù)只有一個(gè)。 requestAnimationFrame 方法讓我們可以在下一幀開始時(shí)調(diào)用指定函數(shù)。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的...
摘要:即在回調(diào)被執(zhí)行前,多次調(diào)用帶有同一回調(diào)函數(shù)的,會(huì)導(dǎo)致回調(diào)在同一幀中執(zhí)行多次。例子中的是由傳給回調(diào)函數(shù)的,表示回調(diào)隊(duì)列被觸發(fā)的時(shí)間。完美的解決方案是通過(guò)來(lái)管理隊(duì)列,其思路就是保證的隊(duì)列里,同樣的回調(diào)函數(shù)只有一個(gè)。 requestAnimationFrame 方法讓我們可以在下一幀開始時(shí)調(diào)用指定函數(shù)。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的...
摘要:即在回調(diào)被執(zhí)行前,多次調(diào)用帶有同一回調(diào)函數(shù)的,會(huì)導(dǎo)致回調(diào)在同一幀中執(zhí)行多次。例子中的是由傳給回調(diào)函數(shù)的,表示回調(diào)隊(duì)列被觸發(fā)的時(shí)間。完美的解決方案是通過(guò)來(lái)管理隊(duì)列,其思路就是保證的隊(duì)列里,同樣的回調(diào)函數(shù)只有一個(gè)。 requestAnimationFrame 方法讓我們可以在下一幀開始時(shí)調(diào)用指定函數(shù)。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的...
摘要:即在回調(diào)被執(zhí)行前,多次調(diào)用帶有同一回調(diào)函數(shù)的,會(huì)導(dǎo)致回調(diào)在同一幀中執(zhí)行多次。例子中的是由傳給回調(diào)函數(shù)的,表示回調(diào)隊(duì)列被觸發(fā)的時(shí)間。完美的解決方案是通過(guò)來(lái)管理隊(duì)列,其思路就是保證的隊(duì)列里,同樣的回調(diào)函數(shù)只有一個(gè)。 requestAnimationFrame 方法讓我們可以在下一幀開始時(shí)調(diào)用指定函數(shù)。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的...
摘要:即在回調(diào)被執(zhí)行前,多次調(diào)用帶有同一回調(diào)函數(shù)的,會(huì)導(dǎo)致回調(diào)在同一幀中執(zhí)行多次。例子中的是由傳給回調(diào)函數(shù)的,表示回調(diào)隊(duì)列被觸發(fā)的時(shí)間。完美的解決方案是通過(guò)來(lái)管理隊(duì)列,其思路就是保證的隊(duì)列里,同樣的回調(diào)函數(shù)只有一個(gè)。 requestAnimationFrame 方法讓我們可以在下一幀開始時(shí)調(diào)用指定函數(shù)。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的...
閱讀 2513·2023-04-25 22:09
閱讀 1025·2021-11-17 17:01
閱讀 1566·2021-09-04 16:45
閱讀 2622·2021-08-03 14:02
閱讀 821·2019-08-29 17:11
閱讀 3258·2019-08-29 12:23
閱讀 1093·2019-08-29 11:10
閱讀 3283·2019-08-26 13:48