requestAnimationFrame()指南

requestAnimationFrame() is a relatively recent browser API. It gives a more predictable way to hook into the browser render cycle.

requestAnimationFrame()是一个相对较新的浏览器API。 它提供了一种更加可预测的方式来连接浏览器渲染周期。

It’s currently supported by all modern browsers (and IE 10+)

当前所有现代浏览器(和IE 10+)都支持它。

Browser support

It’s not an API specific to animations, but that’s where it is used the most.

它不是特定于动画的API,但是使用最多的地方是动画。

JavaScript has an event loop. It continuously runs to execute JavaScript.

JavaScript有一个事件循环。 它持续运行以执行JavaScript。

In the past, animations were performed using setTimeout() or setInterval(). You perform a little bit of an animation, and you call setTimeout() to repeat again this code in a few milliseconds from now:

过去,动画是使用setTimeout()setInterval() 。 您执行了一点动画,然后调用setTimeout()从现在起的几毫秒内再次重复此代码:

const performAnimation = () => {
  //...
  setTimeout(performAnimation, 1000 / 60)
}
setTimeout(performAnimation, 1000 / 60)

or

要么

const performAnimation = () => {
  //...
}
setInterval(performAnimation, 1000 / 60)

You can stop an animation by getting the timeout or interval reference, and clearing it:

您可以通过获取超时或间隔参考并清除动画来停止动画:

let timer

const performAnimation = () => {
  //...
  timer = setTimeout(performAnimation, 1000 / 60)
}

timer = setTimeout(performAnimation, 1000 / 60)

//...

clearTimeout(timer)

The 1000 / 60 interval between the performAnimation() calls is determined by the monitor refresh rate, which is in most of the cases 60 Hz (60 repaints per second), because it’s useless to perform a repaint if the monitor cannot show it due to its limitations. It leads to ~16.6ms of time we have at our disposal to display every single frame.

1000 / 60之间间隔performAnimation()调用由所述显示器的刷新速率,这是在大多数情况下60赫兹(每秒60重新绘制)来确定,因为它是无用的执行重绘如果显示器不能显示它由于它的局限性。 这将导致我们有大约16.6ms的时间来显示每个帧。

The problem with this approach is that even though we specify this precision accurately, the browser might be busy performing other operations, and our setTimeout calls might not make it in time for the repaint, and it’s going to be delayed to the next cycle.

这种方法的问题在于,即使我们精确地指定了此精度,浏览器也可能正在忙于执行其他操作,而setTimeout调用可能无法及时进行重新绘制,因此它将延迟到下一个周期。

This is bad because we lose one frame, and in the next the animation is performed 2 times, causing the eye to notice the clunky animation.

这很不好,因为我们丢了一帧,在下一帧动画执行了2次,导致眼睛注意到笨拙的动画。

Check this example on Glitch of an animation built using of setTimeout().

使用setTimeout()构建动画的毛刺上检查该示例。

requestAnimationFrame is the standard way to perform animations, and it works in a very different way event though the code looks very similar to the setTimeout/setInterval code:

requestAnimationFrame是执行动画的标准方法,尽管代码看起来与setTimeout / setInterval代码非常相似,但它以一种非常不同的方式工作,即事件:

let request

const performAnimation = () => {
  request = requestAnimationFrame(performAnimation)
  //animate something
}

requestAnimationFrame(performAnimation)

//...

cancelAnimationFrame(request) //stop the animation

This example on Glitch of an animation built using of requestAnimationFrame() shows how.

此示例显示了使用requestAnimationFrame()构建动画的故障示例。

优化 (Optimization)

requestAnimationFrame() since its introduction was very CPU friendly, causing animations to stop if the current window or tab is not visible.

由于requestAnimationFrame()的引入对CPU非常友好,如果当前窗口或选项卡不可见,则会导致动画停止。

At the time requestAnimationFrame() was introduced, setTimeout/setInterval did run even if the tab was hidden, but now since this approach proved to be successful also to battery savings, browsers also implemented throttling for those events, allowing max 1 execution per each second.

在引入requestAnimationFrame()时,即使隐藏了选项卡,setTimeout / setInterval仍可以运行,但是现在由于这种方法在节电方面也很成功,因此浏览器还对这些事件实施了限制,每秒最多执行1次。

Using requestAnimationFrame the browser can further optimize the resource consumption and make the animations smoother.

使用requestAnimationFrame ,浏览器可以进一步优化资源消耗并使动画更流畅。

时间轴示例 (Timeline examples)

This is the perfect timeline if you use setTimeout or setInterval:

如果使用setTimeout或setInterval,则这是理想的时间表:

Perfect timeline

you have a set of paint (green) and render (purple) events, and your code is in the yellow box - by the way, these are the colors used in the Browser DevTools as well to represent the timeline:

您有一组绘画(绿色)和渲染(紫色)事件,并且您的代码在黄色框中-顺便说一下,这些是浏览器DevTools中用来表示时间轴的颜色:

The devtools timeline

The illustration shows the perfect case. You have painting and rendering every 60ms, and your animation happens in between, perfectly regular.

下图显示了理想的情况。 您每60毫秒就有一次绘画和渲染,而动画则介于两者之间,完全规则。

If you used a higher frequency call for your animation function:

如果您为动画功能使用了更高频率的调用:

Too frequent timeline

Notice how in each frame we call 4 animation steps, before any rendering happens, and this will make the animation feel very choppy.

请注意,在进行任何渲染之前,在每个帧中我们如何调用4个动画步骤,这将使动画感觉非常不稳定。

What if setTimeout cannot run on time due to other code blocking the event loop? We end up with a missed frame:

如果setTimeout由于其他代码阻塞事件循环而无法按时运行怎么办? 我们最终错过了帧:

Missed frame

What if an animation step takes a little bit more than you anticipate?

如果动画步骤所花费的时间超出您的预期,该怎么办?

Delay in the timeline

the render and paint events will be delayed as well.

渲染和绘画事件也将被延迟。

This is how requestAnimationFrame() works visually:

这是requestAnimationFrame()直观地工作的方式:

Delay in the timeline

all the animation code runs before the rendering and painting events. This makes for a more predictable code, and there’s a lot of time to do the animation without worrying about going past the 16ms time we have at our disposal.

所有动画代码都渲染和绘画事件之前运行。 这使得代码更加可预测,并且有很多时间来制作动画,而不必担心会超过我们可支配的16ms时间。

Check this great video by Jake Archibald on the topic.

观看有关杰克·阿奇博尔德(Jake Archibald)的精彩视频

翻译自: https://flaviocopes.com/requestanimationframe/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值