requestAnimationFrame 方法你真的用對了嗎棚辽?

requestAnimationFrame 方法讓我們可以在下一幀開始時調(diào)用指定函數(shù)路操。但是很多人可能不知道,不管三七二十一直接在 requestAnimationFrame 的回調(diào)函數(shù)里繪制動畫會有一個問題渠脉。是什么問題呢?要理解這個問題瓶佳,我們先要了解 requestAnimationFrame 的一個知識點。

requestAnimationFrame 不管理回調(diào)函數(shù)

這個知識點就是 requestAnimationFrame 不管理回調(diào)函數(shù)鳞青。這一點在 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

即在回調(diào)被執(zhí)行前,多次調(diào)用帶有同一回調(diào)函數(shù)的 requestAnimationFrame臂拓,會導(dǎo)致回調(diào)在同一幀中執(zhí)行多次厚脉。我們可以通過一個簡單的例子模擬在同一幀內(nèi)多次調(diào)用 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

我們用連續(xù)調(diào)用兩次 requestAnimationFrame 模擬在同一幀中調(diào)用兩次 requestAnimationFrame

例子中的 timestamp 是由 requestAnimationFrame 傳給回調(diào)函數(shù)的胶惰,表示回調(diào)隊列被觸發(fā)的時間傻工。由輸出可知,animation 函數(shù)在同一幀內(nèi)被執(zhí)行了兩次孵滞,即繪制了兩次動畫中捆。然而在同一幀繪制兩次動畫很明顯是多余的,相當(dāng)于畫了一幅畫坊饶,然后再在這幅畫上再畫上同樣的一幅畫泄伪。

問題

那么什么場景下,requestAnimationFrame 會在一幀內(nèi)被多次調(diào)用呢匿级?熟悉事件的同學(xué)應(yīng)該馬上能想到 mousemove, scroll 這類事件蟋滴。

所以前面我們提到的問題就是:因為 requestAnimationFrame 不管理回調(diào)函數(shù),在滾動痘绎、觸摸這類高觸發(fā)頻率的事件回調(diào)里津函,如果調(diào)用 requestAnimationFrame 然后繪制動畫,可能會造成多余的計算和繪制孤页。例如:

window.addEventListener('scroll', e => {
    window.requestAnimationFrame(timestamp => {
        animation(timestamp)
    })
})

在上面代碼中尔苦,scroll 事件可能在一幀內(nèi)多次觸發(fā),所以 animation 函數(shù)可能會在一幀內(nèi)重復(fù)繪制,造成不必要的計算和渲染蕉堰。

解決方法

對于這種高頻發(fā)事件凌净,一般的解決方法是使用節(jié)流函數(shù)。但是在這里使用節(jié)流函數(shù)并不能完美解決問題屋讶。因為節(jié)流函數(shù)是通過時間管理隊列的冰寻,而 requestAnimationFrame 的觸發(fā)時間是不固定的,在高刷新頻率的顯示屏上時間會小于 16.67ms皿渗,頁面如果被推入后臺斩芭,時間可能大于 16.67ms。

完美的解決方案是通過 requestAnimationFrame 來管理隊列乐疆,其思路就是保證 requestAnimationFrame 的隊列里划乖,同樣的回調(diào)函數(shù)只有一個。示意代碼如下:

const onScroll = e => {
    if (scheduledAnimationFrame) { return }

    scheduledAnimationFrame = true
    window.requestAnimationFrame(timestamp => {
        scheduledAnimationFrame = false
        animation(timestamp)
    })
}
window.addEventListener('scroll', onScroll)

但是每次都要寫這么一堆代碼挤土,也有點麻煩琴庵。所以我開源了 raf-plus 庫用于解決這個問題,有需要的的同學(xué)可以用用~

結(jié)論

requestAnimationFrame 不管理回調(diào)函數(shù)隊列仰美,而滾動迷殿、觸摸這類高觸發(fā)頻率事件的回調(diào)可能會在同一幀內(nèi)觸發(fā)多次。所以正確使用 requestAnimationFrame 的姿勢是咖杂,在同一幀內(nèi)可能調(diào)用多次 requestAnimationFrame 時庆寺,要管理回調(diào)函數(shù),防止重復(fù)繪制動畫诉字。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末懦尝,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子壤圃,更是在濱河造成了極大的恐慌陵霉,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件埃唯,死亡現(xiàn)場離奇詭異撩匕,居然都是意外死亡,警方通過查閱死者的電腦和手機墨叛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門止毕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人漠趁,你說我怎么就攤上這事扁凛。” “怎么了闯传?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵谨朝,是天一觀的道長。 經(jīng)常有香客問我,道長字币,這世上最難降的妖魔是什么则披? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮洗出,結(jié)果婚禮上士复,老公的妹妹穿的比我還像新娘。我一直安慰自己翩活,他們只是感情好阱洪,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著菠镇,像睡著了一般冗荸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上利耍,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天蚌本,我揣著相機與錄音,去河邊找鬼隘梨。 笑死魂毁,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的出嘹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼咬崔,長吁一口氣:“原來是場噩夢啊……” “哼税稼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起垮斯,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤郎仆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后兜蠕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扰肌,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年熊杨,在試婚紗的時候發(fā)現(xiàn)自己被綠了曙旭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡晶府,死狀恐怖桂躏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情川陆,我是刑警寧澤剂习,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響鳞绕,放射性物質(zhì)發(fā)生泄漏失仁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一们何、第九天 我趴在偏房一處隱蔽的房頂上張望萄焦。 院中可真熱鬧,春花似錦垂蜗、人聲如沸楷扬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽烘苹。三九已至,卻和暖如春片部,著一層夾襖步出監(jiān)牢的瞬間镣衡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工档悠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留廊鸥,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓辖所,卻偏偏與公主長得像惰说,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子缘回,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容