一、requestAnimationFrame
(rAF)优化动画
1. 核心原理
requestAnimationFrame
是浏览器为动画设计的专用 API,其回调函数会在浏览器下一次重绘之前执行(通常每秒 60 次,与屏幕刷新率同步),确保动画流畅且避免不必要的渲染。
2. 适用场景
- DOM 动画:元素位移、缩放、透明度变化。
- Canvas/WebGL 渲染:游戏、数据可视化。
- 高频交互:滚动、拖拽、手势操作。
3. 优化实践
function animate() {
// 执行动画逻辑(如更新元素位置)
element.style.transform = `translateX(${position}px)`;
// 循环调用以持续动画
position += 1;
requestAnimationFrame(animate);
}
// 启动动画
requestAnimationFrame(animate);
4. 关键优化技巧
- 避免在 rAF 中执行耗时操作:将复杂计算拆分到 Web Workers 或空闲时段。
- 批量 DOM 操作:减少布局抖动(Layout Thrashing)。
-
使用
transform
和opacity
:触发 GPU 加速,跳过重排/重绘。
二、requestIdleCallback
(rIC)优化后台任务
1. 核心原理
requestIdleCallback
允许在浏览器空闲时段执行低优先级任务,避免阻塞关键渲染和事件处理。回调函数接收 IdleDeadline
对象,包含剩余空闲时间(timeRemaining()
)。
2. 适用场景
- 日志上报:用户行为统计。
- 数据预处理:如分页数据预加载。
- 非关键 UI 更新:如侧边栏内容加载。
3. 优化实践
function processTask(deadline) {
while (deadline.timeRemaining() > 0 && tasks.length > 0) {
const task = tasks.pop();
executeTask(task); // 执行单个任务
}
if (tasks.length > 0) {
requestIdleCallback(processTask); // 继续处理剩余任务
}
}
// 启动后台任务
requestIdleCallback(processTask);
4. 关键优化技巧
- 任务分片:将大任务拆分为多个小任务,每次空闲时段处理一部分。
-
超时控制:通过
timeout
参数确保任务最终执行(慎用,可能阻塞主线程)。requestIdleCallback(processTask, { timeout: 1000 }); // 最多等待 1 秒
-
优先级管理:结合
shouldYield
模式判断是否让出主线程。if (deadline.timeRemaining() <= 0) { requestIdleCallback(processTask); // 剩余时间不足,重新调度 return; }
三、协同使用 rAF 和 rIC 的策略
场景示例:滚动列表加载数据
- 滚动动画使用 rAF:确保滚动流畅。
- 数据加载使用 rIC:在空闲时段加载后续数据。
// 处理滚动动画
function handleScroll() {
requestAnimationFrame(() => {
listContainer.style.transform = `translateY(${scrollPos}px)`;
});
}
// 空闲时加载数据
function loadData(deadline) {
while (deadline.timeRemaining() > 0 && hasMoreData) {
fetchNextDataChunk(); // 加载下一块数据
}
if (hasMoreData) {
requestIdleCallback(loadData);
}
}
// 监听滚动事件
window.addEventListener('scroll', handleScroll);
// 初始加载数据
requestIdleCallback(loadData);
四、高级技巧与注意事项
1. 避免常见陷阱
问题 | 解决方案 |
---|---|
rAF 中阻塞主线程 | 将复杂逻辑移至 Web Workers 或分帧处理。 |
rIC 任务未完成 | 记录任务状态,下次空闲时继续处理。 |
过度使用 rIC | 限制后台任务数量,避免长期占用空闲时段。 |
2. 兼容性处理
-
rAF 降级:用
setTimeout
模拟(无法保证帧率)。const rAF = window.requestAnimationFrame || (cb => setTimeout(cb, 1000/60));
-
rIC 降级:用
setTimeout
或立即执行。const rIC = window.requestIdleCallback || (cb => setTimeout(() => cb({ timeRemaining: () => Infinity }), 0));
3. 性能监控
-
Chrome DevTools:
- Performance 面板:分析动画帧率(FPS)和任务执行时间。
- Scheduling 面板:查看空闲时段利用率。
-
Long Tasks API:检测超过 50ms 的任务。
const observer = new PerformanceObserver(list => { list.getEntries().forEach(entry => { console.log('Long task:', entry.duration); }); }); observer.observe({ entryTypes: ['longtask'] });
五、总结
-
requestAnimationFrame
:为动画设计,确保与屏幕刷新同步,避免丢帧。 -
requestIdleCallback
:处理后台任务,利用空闲时间,避免阻塞关键操作。 -
协作模式:
- 动画/交互 → rAF 优先,保证流畅性。
- 非关键任务 → rIC 调度,提升整体响应速度。
通过合理分配任务优先级和资源,可显著提升复杂 Web 应用的性能和用户体验。