requestAnimationFrame 要领你真的用对了吗?

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 时,要治理回调函数,防备反复绘制动画。

    原文作者:前端菜鸟
    原文地址: https://segmentfault.com/a/1190000010229232
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞