requestAnimationFrame()
1. 引言
requestAnimationFrame 是浏览器提供的用于在下一次重绘之前执行指定回调函数的 API。它通常用于创建流畅的 JavaScript 动画,能自动与浏览器的刷新率同步(通常是 60Hz,即约 16.6ms 执行一次)。
2. 工作原理
- 浏览器每帧都会执行“重绘”操作(例如改变元素位置、样式)。
requestAnimationFrame将回调放入一个队列,在每一帧的绘制之前执行该回调。- 如果回调中再次调用
requestAnimationFrame,就会形成递归循环,持续与屏幕刷新频率保持一致。
3. 与 setTimeout / setInterval 的区别
| 对比维度 | requestAnimationFrame | setTimeout/setInterval |
|---|---|---|
| 执行时机 | 帧开始前,由浏览器决定(与屏幕刷新同步) | 宏任务队列,按指定延迟执行,与帧无关 |
| 频率 | 匹配显示器刷新率(通常 60fps) | 不可控,即使设为 16.6ms,也可能因事件队列阻塞而漂移 |
| 性能 | 页面隐藏/非激活时自动暂停,节省 CPU/电量 | 后台依然执行,浪费资源 |
| 丢帧处理 | 浏览器会自动合并同帧内的多次 DOM 修改 | 容易丢帧或产生无效更新 |
| 精确性 | 高(基于 vsync 信号) | 低(受事件循环影响,最小延迟约 4ms) |
4. 优点(为什么用 rAF 做动画)
- 流畅:与刷新率同步,避免掉帧或过度绘制。
- 高效:页面不可见时自动停止,不消耗资源。
- 精准时间戳:回调参数
timestamp为高精度时间,可用于计算帧间差值。 - 批量更新:浏览器可以合并同一帧内的样式计算和布局,减少重排。
5. 使用场景
- JavaScript 动画:如移动、缩放、渐变等高频属性修改。
- Canvas/WebGL 渲染:游戏、粒子效果、实时图表。
- 滚动监听优化:配合滚动事件实现平滑视差效果。
- 帧率监测:计算 FPS。
- 与
setTimeout组合实现限流:例如在 rAF 中做 DOM 批量更新。
6. 注意事项 / 潜在缺点
- 需要递归调用:不像
setInterval自动重复,必须手动在回调末尾再次调用。 - 不适合低频率任务:例如每隔几秒请求数据,应使用
setInterval。 - 兼容性:IE10 及以上均支持,旧版需降级(
setTimeout回退)。 - 高频率回调:如果回调执行时间超过 16.6ms,会导致丢帧,需优化代码。