如果我们在requestAnimationFrame中操作DOM,会发生什么



我的理解是,只要有一些DOM操作,比如插入DOM元素,就会触发回流,很可能随后会重新绘制。如果我错了,请纠正我。引用MDN Web文档,

window.requestAnimationFrame((方法告诉浏览器您希望执行动画,并请求浏览器在下一次重新绘制之前调用指定的函数来更新动画

requestAnimationFrame(又名aAF(回调在浏览器即将重新绘制之前调用。这是否意味着,如果我们设法在这个rAF中进行DOM操作(编辑:并在最后对另一个rAF进行排队(,每次都会触发回流,从而重新绘制,那么我们将陷入一个无限循环,而不会在屏幕上实际渲染任何内容。

或者,一旦浏览器决定重新绘制,它就会坚持下去,并在下一次重新绘制中应用RAF回调中发生的任何更新?

只要有一些DOM操作,比如插入DOM元素,就会触发回流,很可能随后会重新绘制

绘画动作异步发生,因此"触发器";应该这样理解。首先,您的JavaScript代码将在实际发生之前完成。

如果我们设法在这个rAF中进行DOM操作(编辑:并在最后对另一个rAF进行排队(,每次都会触发回流,从而重新绘制,我们将陷入无限循环,而不会在屏幕上实际渲染任何内容。

重新绘制的需求会累积,并且不会同步满足。首先,您的代码必须完成,直到调用堆栈为空。所以这里没有无限循环。

或者,一旦浏览器决定重新绘制,它就会坚持下去,并在下一次重新绘制中应用RAF回调中发生的任何更新?

是。当调用RAF回调时,该代码获得了对DOM进行更新的最后机会,这可能会进一步积累绘画需求。如果在该回调中,您还在RAF上注册了另一个回调,它将不会在那时执行,而是稍后执行:在下一个时间,浏览器将准备其重新绘制任务,所以不是当前任务。

简化示例

假设你有这个代码:

requestAnimationFrame(update);
myElement.style.backgroundColor = "silver"; // This queues a need for repaint
function update() {
// This queues a need for repaint
myElement.style.width = Math.floor(Math.random() * 100) + "px";
requestAnimationFrame(update);
}

当它执行时,我们得到以下序列:

  1. update注册为回调
  2. 背景更改安排了重新绘制的需要
  3. 调用堆栈变为空
  4. 浏览器启动其重新绘制作业,但考虑到存在已注册的回调。因此,它删除了这个注册(因为它应该只运行一次(,并在执行其他操作之前执行update
  5. 宽度更改安排了重新绘制的需要。更改列表现在包括背景更改、宽度更改以及已计算的任何级联效应。(如何表示取决于浏览器(
  6. update函数再次注册为回调
  7. 浏览器现在检查作为重新绘制工作的一部分需要做什么,并执行可视化背景和宽度变化的效果所需的所有操作
  8. 油漆工作结束。只剩下已注册的update回调
  9. 当浏览器执行下一个绘制周期时,我们从步骤4再次开始,但现在不再有排队的背景更改。剩下的都是同样的过程

相关内容

最新更新