返回
创建于
状态
公开

当主线程(Main Thread)被阻塞时(例如执行了一个死循环或耗时极长的同步任务),JS 的 requestAnimationFrame (rAFA) 必定会停止执行,而 CSS Keyframes 动画是否执行则取决于它作用的属性

这是由浏览器渲染架构决定的,我们可以从以下两个维度来拆解:


1. JS 的 requestAnimationFrame

结论:会被完全阻塞。

  • 原理requestAnimationFrame 的回调函数是运行在主线程上的。
  • 渲染流水线:在浏览器的事件循环(Event Loop)中,rAFA 的触发时机是在“样式计算”和“布局”之前。
  • 结果:既然主线程正忙于处理那个阻塞任务,它就没有余力去切换到 Event Loop 的渲染阶段。因此,rAFA 的回调会被推迟,直到阻塞任务完成,这通常表现为动画卡死或直接跳帧。

2. CSS Keyframes 动画

结论:部分执行(取决于属性是否能被“合成器”处理)。

现代浏览器(Chrome/Edge/Safari)拥有合成器线程(Compositor Thread),它独立于主线程运行。

A. 会被阻塞的情况

如果你的 CSS 动画涉及需要主线程参与的属性(即触发了 LayoutPaint 的属性):

  • 例子width, height, margin, top/left (非定位), color
  • 原因:这些属性的改变需要重新计算布局(Reflow)或重新绘制(Repaint),这些工作必须在主线程完成。如果主线程阻塞,动画就会停滞。

B. 不会被阻塞的情况(硬件加速)

如果你使用了合成器属性

  • 例子transform (scale, rotate, translate) 和 opacity
  • 原因:浏览器会将这些元素提升到独立的合成层(Compositor Layer)
  • 结果:一旦动画开始,主线程会把动画的路径、时间曲线等信息交给合成器线程和 GPU。即使随后主线程死锁,合成器线程依然可以独立地在每一帧计算位移并提交给 GPU 渲染。

总结对比

特性是否受主线程阻塞影响运行位置场景建议
requestAnimationFrame受影响(停止)主线程需要复杂逻辑计算、与 JS 状态强绑定的动画
CSS 动画 (Layout 属性)受影响(停止)主线程简单的 UI 状态切换(如宽高改变)
CSS 动画 (Transform/Opacity)不受影响(流畅)合成器线程/GPU性能优先的平滑位移、旋转、缩放动画

验证方法

你可以做一个简单的实验:

  1. 写一个 infinite rotate 的 CSS 动画(使用 transform)。
  2. 写一个 requestAnimationFrame 改变数值的脚本。
  3. 在控制台运行 while(true){}。 你会发现,JS 计数器停了,但页面上的转圈动画可能依然在丝滑旋转。