requestIdleCallback 与 requestAnimationFrame 实战指南:掌控任务调度的两把利刃!

197 阅读3分钟

⏱ 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 中的应用建议

框架动画 / 视觉更新空闲任务
ReactrAF 中更新 setState 节奏useEffect + rIC 延迟操作
VuenextTick + 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);
};

🧠 总结对比表

对比维度requestAnimationFramerequestIdleCallback
调度频率每帧调用(16.7ms)空闲时调用(不固定)
任务适用动画绘制、位移、过渡等非关键任务、预处理、缓存等
是否影响页面流畅度❌ 可能,如果任务过重✅ 避免卡顿(除非任务超大)
是否受页面可见性影响✅ 背景页暂停✅ 背景页暂停
兼容性✅ 所有主流浏览器支持⚠️ Firefox/Safari 不支持,需降级

✅ 最佳实践建议

  1. ✅ 动画/UI → requestAnimationFrame
  2. ✅ 日志/缓存/预加载 → requestIdleCallback
  3. ✅ 配合 IntersectionObserver 做懒加载更丝滑
  4. ✅ 长列表、埋点、WebVitals 收集中分流任务节奏

✨ 一句话总结:

requestAnimationFrame 是让 UI 更丝滑的时间节拍器,而 requestIdleCallback 是提升性能的浏览器缝隙利用器

前者负责「动得好」,后者负责「做得巧」!

👍 如果你觉得这篇文章有帮助,欢迎点赞、关注、收藏,后续我会努力更新更多的前端优化方面的实用技巧。