为什么建议在重新绘制后使用requestAnimationFrame嵌套setTimeout来安排任务?

11
Mozilla前端工程师性能最佳实践文档中,建议将setTimeoutrequestAnimationFrame结合使用,在重绘后立即运行某些内容:
requestAnimationFrame(() => {
  setTimeout(() => {
    // This code will be run ASAP after Style and Layout information have
    // been calculated and the paint has occurred. Unless something else
    // has dirtied the DOM very early, querying for style and layout information
    // here should be cheap.
  }, 0);
});

为什么这是推荐的解决方案?是什么使得这成为在重新绘制后安排某事的最佳方式?


当您为DOM设置新的(布局)值时,DOM不会重新计算,只有在更改DOM后读取值或在重新绘制之前才会进行重新计算。定时函数很可能会给您一个未更改的DOM,即它已经被计算好了,并且读取值不会导致重新计算,因为定时函数将在重新绘制后立即调用。 - Teemu
在这里查询样式和布局信息应该很便宜。没有页面重新流动、计算等等... - Peter
1个回答

8
为什么这是推荐的解决方案?到底是什么使得这成为在重绘后立即安排任务的最佳方式?
在重绘后立即运行代码可以最大程度地确保DOM已经完全计算,从而最小化查询DOM可能导致昂贵回流的机会。如果您不打算查询DOM,则无需担心此问题。
requestAnimationFrame将安排代码在重绘之前立即运行,接近您想要的位置但不完全相同。因此,在0毫秒(或在支持它的浏览器上使用setImmediate)内执行setTimeout将尽快执行代码。这不能保证您的代码是重绘后第一个运行的内容,但在您可用的API中,这是最好的选择。

你说 requestAnimationFrame 会在重绘之前立即安排代码运行,但它可能会在同一帧内多次调用提供的回调函数,对吗?如果它可以在同一帧内多次调用回调函数,那么如何保证在重绘之前正确运行呢? - user5918874
如果您只调用一次 requestAnimationFrame,那么您应该只会得到一个回调。 - Nicholas Tower
如果您在requestAnimationFrame回调中进行另一个requestAnimationFrame调用,那么第二个调用将发生在下一帧而不是当前帧。 - Nicholas Tower
正如我所说的,当在requestAnimationFrame回调函数中调用requestAnimationFrame时,它会等待到下一帧。您每次只会得到一个回调。 - Nicholas Tower
啊,好的,我现在明白了。他们是在谈论多次调用requestAnimationFrame,但不是在回调函数内部。只是多个无关的调用。感谢您的解释,现在很清楚了。 - user5918874
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接