我将把我的评论转换成答案,这样我就可以更好地格式化它,并希望将来也能帮助别人。我不明确建议将我的答案标记为正确,但我认为这个答案应该与这个问题一起出现。
这篇文章应该给你一些背景故事requestAnimationFrame
: http://www.javascriptkit.com/javatutors/requestanimationframe.shtml http://www.javascriptkit.com/javatutors/requestanimationframe.shtml.
我建议阅读上面链接的文章,然后阅读我的答案。
我只会明确提及requestAnimationFrame
可能看起来类似于setTimeout(() => {}, 0)
,但如果你有一部 1985 年生产的 Zack Morris 手机,它的“尽快”可能会晚 5 秒,从而使你的动画看起来很糟糕,类似于电子游戏中你的角色在屏幕上滞后的情况。该函数可能在正确的时间被调用,但实际上并没有在正确的时间执行。
想象一下收集阶段和渲染阶段会很有帮助。抱歉,我不知道这个东西的确切术语,但我认为人眼可以在 20 FPS 下看到平滑的运动,但这意味着你有 20 个“帧”,所以就像计算了 20 次一样。这就像每秒 20 次聚集一群孩子并将他们推入公共汽车。将它们推入公共汽车是一个事件,这类似于重新绘制屏幕。有时,孩子们可能会被落在后面,而下一次就会有更多的孩子被接走,所以你可以想象随着时间的推移,感知流程的流畅度会得到怎样的提升。
值得注意的是,优化是针对下一次重新绘制或下一次屏幕“更改”时进行的。requestAnimationFrame
确实在幕后工作,以确保动画在正确的时间发生并且平滑,这意味着像素在正确的时间位于应有的位置。 (我认为,如果您查看“什么是卡顿动画”的定义,并查看一些围绕该问题的讨论,您会获得很多意义。我提到这一点是因为我们想更多地了解重画过程以及什么各种事情很重要以及为什么)
我记得requestAnimationFrame
可以放弃为时已晚的计算。例如,如果单击按钮,像素会从 0% 到 25% 到 50% 到 75% 到 100%(某种任意距离计算)。我们可以说,1 秒后,像素应该已经移动了 50% 的距离,2 秒后,它应该达到 100%,即最终的静止位置。
像素在正确的时间位于正确的位置比它们准确地到达它们应该到达的每个位置更重要。requestAnimationFrame
正在帮助您做到这一点。如果屏幕即将重新绘制,并且“它”需要运行一个需要太长时间的计算,“它”就会忽略它并跳到下一帧。这就像通过减脂来保持步伐一样,从而避免卡顿。
requestAnimationFrame
无论是在 Web 浏览器、iOS 还是 Android 中,它都是针对相同挑战的解决方案。他们都一遍又一遍地重复这个绘制屏幕的过程。您可以开始计算下一次重新绘制所需的内容,但开始得太晚,因此在下一次重新绘制发生时尚未完成。
想象一下,你的动画很流畅,但你的手机突然收到 20 条推送通知,导致 CPU 陷入困境,导致你的动画延迟16.7 milliseconds
。而不是在错误的时间在正确的位置显示像素,requestAnimationFrame
通过使像素在正确的时间位于正确的位置来提供帮助,但它可能会发挥一些魔力,甚至有时在本来应该绘制像素的情况下不尝试绘制像素,从而节省性能并提高性能感知到的平滑度。
我刚刚意识到这是一面文字墙,但我认为它会提供信息。
这些重绘大约每秒发生 60 帧,因此requestAnimationFrame
当计算出最佳时间时,每秒可以发射 60 次。 1 秒有 1000 毫秒,所以 60 FPS 就是每帧一帧16.7ms
。如果人眼在 20FPS 时感知到平滑度,那么理论上您可以每 45 毫秒或 30% 重新绘制一次,并且动画仍然会平滑。
我的定义可能不准确,但我希望它们可以帮助您了解正在发生的事情。