requestAnimationFrame和requestIdleCallback分别是什么,是用在什么场景下

深入解析 requestAnimationFramerequestIdleCallback


requestAnimationFrame (rAF)requestIdleCallback (rIC) 都是浏览器提供的 异步调度 API,但它们的执行时机和用途完全不同。

API 主要用途 何时执行 是否保证执行 适合场景
requestAnimationFrame 高优先级 UI 更新 下一帧渲染前(通常 16.67ms 内) 一定执行(下一帧到来时) 动画、滚动、WebSocket 实时数据可视化
requestIdleCallback 低优先级任务 浏览器空闲时(时间不确定) 不一定执行(如果浏览器一直忙) 预加载、日志统计、AI 计算、非关键数据处理

1. requestAnimationFrame (rAF):下一帧渲染前执行

🔹 工作原理

浏览器的 渲染帧率 一般是 60Hz ,即 每 16.67ms 需要完成一次绘制(包括 JS 计算、样式计算、布局、绘制等)。

  • requestAnimationFrame 会在下一帧开始前执行 ,保证代码在下一帧渲染前完成,不会阻塞 UI

  • 适用于 高频 UI 更新,比如:

    • CSS 动画
    • 页面滚动
    • WebSocket 高频推送的数据可视化
    • Canvas 绘图

🔹 示例 1:流畅动画

ini 复制代码
let box = document.getElementById("box");
let position = 0;

function move() {
  position += 5;
  box.style.transform = `translateX(${position}px)`;

  if (position < 300) {
    requestAnimationFrame(move); // 递归调用,持续更新
  }
}

requestAnimationFrame(move);

为什么使用 requestAnimationFrame

  • 不卡顿:会在合适的时间点执行,不会阻塞主线程。
  • 不影响页面性能:浏览器空闲时自动暂停,节省资源。

🔹 示例 2:WebSocket 高频推送数据

ini 复制代码
let pending = false;

socket.onmessage = (event) => {
  const data = JSON.parse(event.data);

  if (!pending) {
    pending = true;
    requestAnimationFrame(() => {
      updateUI(data);
      pending = false;
    });
  }
};

function updateUI(data) {
  document.getElementById("output").innerText = JSON.stringify(data);
}

📌 避免 UI 频繁更新,导致卡顿

  • 如果 WebSocket 每 1ms 推送一次数据,直接更新 DOM 会让页面卡死。
  • 使用 requestAnimationFrame 让 UI 更新保持在 60FPS 以内,保证流畅度。

🔹 示例 3:滚动优化

监听 scroll 事件时,直接操作 DOM 可能导致页面卡顿,应该用 requestAnimationFrame 优化:

ini 复制代码
let ticking = false;

window.addEventListener("scroll", () => {
  if (!ticking) {
    requestAnimationFrame(() => {
      updateScrollPosition(window.scrollY);
      ticking = false;
    });
    ticking = true;
  }
});

function updateScrollPosition(scrollY) {
  document.getElementById("position").innerText = scrollY;
}

📌 好处 :避免 scroll 事件触发过于频繁,优化滚动时的 UI 更新。


2. requestIdleCallback (rIC):浏览器空闲时执行

🔹 工作原理

  • requestIdleCallback 让浏览器在 主线程空闲时 执行低优先级任务。

  • 执行时间不固定,取决于浏览器的空闲情况:

    • 如果用户在快速滚动 ,可能不会触发 requestIdleCallback
    • 如果 CPU 负载高,可能很久都不会执行。

🔹 示例 1:处理后台任务

scss 复制代码
function heavyTask(deadline) {
  while (deadline.timeRemaining() > 0) {
    console.log("执行低优先级任务...");
  }

  requestIdleCallback(heavyTask);
}

requestIdleCallback(heavyTask);

📌 deadline.timeRemaining() 返回本次空闲时间的剩余毫秒数,避免影响 UI 交互。


🔹 示例 2:懒加载数据

当页面加载完毕后,在空闲时间预加载一些不重要的数据:

javascript 复制代码
requestIdleCallback(() => {
  fetch("/api/data").then(res => res.json()).then(data => {
    console.log("预加载数据完成:", data);
  });
});

📌 好处:不影响页面主线程,提高用户体验。


🔹 示例 3:日志上报

scss 复制代码
requestIdleCallback(() => {
  sendAnalyticsData();
});

📌 好处:浏览器空闲时再上传日志,避免影响用户体验。


3. requestAnimationFrame vs requestIdleCallback:何时用哪一个?

场景 requestAnimationFrame requestIdleCallback
动画 ✅ 需要流畅动画 ❌ 不能保证执行时间
高频 WebSocket 数据 ✅ 控制 UI 更新频率 ❌ 可能无法及时更新
页面滚动 ✅ 监听 scroll 事件 ❌ 不能保证执行时机
后台任务(日志、数据计算) ❌ 影响 UI 体验 ✅ 浏览器空闲时执行
预加载数据 ❌ 影响用户交互 ✅ 在用户空闲时加载
AI 计算 ❌ 主线程压力大 ✅ 只有空闲时才执行

4. 如何组合使用?

🔹 WebSocket 高速数据流 + UI 更新优化

ini 复制代码
let pending = false;
let backgroundData = [];

socket.onmessage = (event) => {
  const data = JSON.parse(event.data);
  backgroundData.push(data);

  // 让 UI 更新不超过 60FPS
  if (!pending) {
    pending = true;
    requestAnimationFrame(() => {
      updateUI(backgroundData);
      backgroundData = [];
      pending = false;
    });
  }

  // 在浏览器空闲时处理日志
  requestIdleCallback(() => {
    processLogs(backgroundData);
  });
};

function updateUI(data) {
  console.log("更新 UI", data);
}

function processLogs(data) {
  console.log("后台处理数据", data);
}

📌 优化点

  1. requestAnimationFrame 让 UI 更新流畅,不会因 WebSocket 高频推送导致页面卡死
  2. requestIdleCallback 在浏览器空闲时处理日志,避免影响 UI 渲染

5. 总结

  • requestAnimationFrameUI 渲染优化 ,适用于 动画、滚动、WebSocket UI 更新
  • requestIdleCallback后台任务调度 ,适用于 日志、预加载、AI 计算
  • 两者结合使用,可以优化高性能应用,提升页面流畅度和用户体验! 🚀
相关推荐
黑臂麒麟3 分钟前
Electron for OpenHarmony 跨平台实战开发:Electron 文件系统操作实战
前端·javascript·electron·openharmony
1024肥宅10 分钟前
工程化工具类:模块化系统全解析与实践
前端·javascript·面试
weixin_4225554213 分钟前
ezuikit-js官网使用示例
前端·javascript·vue·ezuikit-js
running up1 小时前
Java集合框架之ArrayList与LinkedList详解
javascript·ubuntu·typescript
xiaoxue..1 小时前
React 之 Hooks
前端·javascript·react.js·面试·前端框架
Alair‎1 小时前
300TypeScript基础知识
javascript
莫物1 小时前
element el-table表格 添加唯一标识
前端·javascript·vue.js
Shirley~~1 小时前
PPTist 幻灯片工具栏Toolbar部分
开发语言·前端·javascript
|晴 天|1 小时前
Promise 与 async/await 错误处理最佳实践指南
开发语言·前端·javascript
苹果电脑的鑫鑫1 小时前
.eslintrc.js这个文件作用
开发语言·javascript·ecmascript