📌 1. requestAnimationFrame 执行时机:
✅ 执行在“渲染前”
准确地说:它是在浏览器准备执行下一次渲染(repaint)之前执行的,也就是在 “渲染前的最后一个时刻”。
🔄 一帧的流程大概是:
上一帧结束 →
执行 JS(包括 rAF 回调) →
样式计算 →
布局 →
绘制(Painting) →
下一帧开始
所以:
requestAnimationFrame 的回调会在一次完整渲染周期的开始阶段执行(也就是渲染前)。
这就是为什么它适合做动画:你可以在它里边计算动画状态,浏览器接着就会用你更新后的状态去绘制。
📌 2. requestIdleCallback 执行时机:
✅ 执行在“主线程空闲”期间
也就是说:
- 浏览器 完成了一帧的渲染
- 主线程暂时没有高优先级任务
- 有空余时间(比如 50ms 里还有 10ms 没用)
就会执行你注册的 requestIdleCallback
的回调函数。
🚧 有个限制:
- 它不保证每帧都执行(因为不一定有空闲时间)
- 可以设置
timeout
参数来强制在一定时间内执行(防止永远不执行)
❗ 所以:
requestIdleCallback 是在“渲染之后”的空闲时间才执行的,不影响渲染性能。
📌 3. 每一轮 Event Loop 都会伴随渲染吗?
❌ 不一定!
渲染(也就是 Repaint / Reflow)只会发生在有“视觉变更”的时候。
浏览器默认是 60 帧/秒,也就是 每 16.6ms 才“最多”渲染一次。
如果一轮 Event Loop 没有 UI 变化(比如只是计算数据、发请求等),浏览器就会跳过这一帧的渲染,节省资源。
✅ 总结一句话记忆:
项目 | 执行阶段 | 是否每帧都执行 | 用途 |
---|---|---|---|
requestAnimationFrame |
渲染前 | 是(下一帧前) | 动画更新 |
requestIdleCallback |
渲染后空闲时 | 否(不一定) | 后台任务 |
每轮 Event Loop 是否渲染 | ❌ 不一定 | - | 仅当有视觉变化时 |