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 计算
  • 两者结合使用,可以优化高性能应用,提升页面流畅度和用户体验! 🚀
相关推荐
m0_616188492 小时前
使用vue3-seamless-scroll实现列表自动滚动播放
开发语言·javascript·ecmascript
湛海不过深蓝2 小时前
【ts】defineProps数组的类型声明
前端·javascript·vue.js
layman05282 小时前
vue 中的数据代理
前端·javascript·vue.js
layman05283 小时前
vue中理解MVVM
前端·javascript·vue.js
一舍予4 小时前
八股文-js篇
开发语言·前端·javascript
Edward Nygma6 小时前
springboot3+vue3融合项目实战-大事件文章管理系统-更新用户密码
android·开发语言·javascript
sunbyte6 小时前
Three.js + React 实战系列 - 职业经历区实现解析 Experience 组件✨(互动动作 + 3D 角色 + 点击切换动画)
javascript·react.js·3d
strongwyy6 小时前
DA14585墨水屏学习(2)
前端·javascript·学习
球球和皮皮7 小时前
Babylon.js学习之路《一、初识 Babylon.js:什么是 3D 开发与 WebGL 的完美结合?》
javascript·3d·前端框架·ar·vr
冬阳春晖7 小时前
web animation API 锋利的css动画控制器 (更新中)
前端·javascript·css