⏱ requestIdleCallback 与 requestAnimationFrame 实战指南:掌控任务调度的两把利刃!
你是否遇到动画卡顿?是否异步任务阻塞了用户交互?合理使用浏览器的调度 API,可以将「性能关键任务」与「非关键任务」完美分离,让你页面丝滑、不卡顿、响应快!
🧠 基本概念:这两个 API 做什么的?
| API | 作用 | 适合任务类型 |
|---|---|---|
requestAnimationFrame | 在下一帧绘制前执行回调(约 60fps) | 动画更新、位移动画 |
requestIdleCallback | 浏览器空闲时执行回调(非紧急任务) | 日志收集、预加载、缓存 |
📦 基本语法对比
// rAF:用于动画更新
requestAnimationFrame((timestamp) => {
drawFrame(timestamp);
});
// rIC:用于空闲时运行
requestIdleCallback((deadline) => {
while (deadline.timeRemaining() > 0 && tasks.length > 0) {
doHeavyTask();
}
});
🎯 场景一:高性能动画推荐使用 rAF
let pos = 0;
function move() {
pos += 1;
box.style.transform = `translateX(${pos}px)`;
requestAnimationFrame(move);
}
move();
✅ 动画将与浏览器刷新节奏同步(大多数浏览器约 16.7ms 一帧)
⚠️ 为什么不能用 setTimeout 做动画?
// ❌ 可能丢帧,不与刷新节奏对齐
setInterval(() => {
pos += 1;
box.style.left = pos + 'px';
}, 16);
🎯 场景二:后台任务 / 非关键逻辑使用 rIC
requestIdleCallback((idle) => {
while (idle.timeRemaining() > 0) {
cachePageData();
syncLogsToStorage();
}
});
📌 用它来执行:
- ✅ 用户行为日志记录
- ✅ 本地缓存操作
- ✅ 非核心预渲染/预加载逻辑
🧱 实战案例一:首屏加载优化策略
// 首屏渲染逻辑
renderHeroSection();
// 非关键数据延后处理
requestIdleCallback(() => {
loadSuggestions();
reportLoadTime();
});
✅ 页面加载时优先渲染核心内容,其它辅助模块“等浏览器空了再说”。
⚛️ React/Vue 中的应用建议
| 框架 | 动画 / 视觉更新 | 空闲任务 |
|---|---|---|
| React | rAF 中更新 setState 节奏 | useEffect + rIC 延迟操作 |
| Vue | nextTick + rAF 联合动画 | watch + rIC 执行缓存或日志操作 |
onMounted(() => {
requestIdleCallback(() => {
localStorage.setItem('session', JSON.stringify(data));
});
});
🧪 实战案例二:长列表懒加载 + 空闲日志同步
window.addEventListener('scroll', () => {
if (isNearBottom()) {
loadNextPage(); // 正常加载数据
requestIdleCallback(() => {
updateViewLog(); // 延迟记录埋点日志
});
}
});
💡 requestIdleCallback 限制和兼容性
- Chrome / Edge ✅ 完整支持
- Firefox ❌ 不支持(可用 polyfill)
- Safari ❌ 不支持(iOS 尤其需降级)
✅ 降级处理方式
const ric = window.requestIdleCallback || function (cb) {
return setTimeout(() => cb({ timeRemaining: () => 50 }), 1);
};
🧠 总结对比表
| 对比维度 | requestAnimationFrame | requestIdleCallback |
|---|---|---|
| 调度频率 | 每帧调用(16.7ms) | 空闲时调用(不固定) |
| 任务适用 | 动画绘制、位移、过渡等 | 非关键任务、预处理、缓存等 |
| 是否影响页面流畅度 | ❌ 可能,如果任务过重 | ✅ 避免卡顿(除非任务超大) |
| 是否受页面可见性影响 | ✅ 背景页暂停 | ✅ 背景页暂停 |
| 兼容性 | ✅ 所有主流浏览器支持 | ⚠️ Firefox/Safari 不支持,需降级 |
✅ 最佳实践建议
- ✅ 动画/UI →
requestAnimationFrame - ✅ 日志/缓存/预加载 →
requestIdleCallback - ✅ 配合
IntersectionObserver做懒加载更丝滑 - ✅ 长列表、埋点、WebVitals 收集中分流任务节奏
✨ 一句话总结:
requestAnimationFrame是让 UI 更丝滑的时间节拍器,而requestIdleCallback是提升性能的浏览器缝隙利用器。
前者负责「动得好」,后者负责「做得巧」!
👍 如果你觉得这篇文章有帮助,欢迎点赞、关注、收藏,后续我会努力更新更多的前端优化方面的实用技巧。