前端学习18 requestldleCallback和requestAnimationFrame

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

注意:requestIdleCallback()既不属于宏任务,也不属于微任务。

requestAnimationFrame()

  • 用途:高优先级更新
  • 执行:下一帧渲染前(通常在16.67ms之内)
  • 一定执行(下一帧到来时)
  • 适合场景:动画、滚动、WebSocket实时数据可视化

requestIdleCallback()

  • 用途:低优先级任务
  • 执行:浏览器空闲时(时间不确定)
  • 不一定执行(如果浏览器一直忙)
  • 适合场景预加载、日志统计、AI计算、非关键数据处理

1. requestAnimationFrame(rAF)

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

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

适合于高频UI更新,例如: CSS动画、页面滚动、WebSocket高频推送的数据可视化、Canvas绘图。

示例代码1:流畅动画

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);

优点:

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

实例代码2:WebSocket 高频推送数据

let pending = false;

//当 WebSocket 收到来自服务器的消息时触发。
socket.onmessage = (event) => {
  const data = JSON.parse(event.data);

  if (!pending) {
    pending = true;
	//将 updateUI(data) 的执行推迟到浏览器下一帧绘制前。
	//这意味着无论 WebSocket 收到多少条消息,一帧内只会更新一次 UI。
    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 优化:

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:处理后台任务

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

  requestIdleCallback(heavyTask);
}

requestIdleCallback(heavyTask);

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

示例代码2:懒加载数据

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

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

优点:不影响页面主线程,提高用户体验。

示例代码3:日志上传

requestIdleCallback(() => {
  sendAnalyticsData();
});

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

全部评论

相关推荐

03-26 13:44
南华大学 Java
在看面经的花生米很野蛮:这种情况下你当然要回答,你也是吗!!!!我超喜欢他的XXXXX
点赞 评论 收藏
分享
抱抱碍事梨a:三点建议,第一点是建议再做一个项目,把自我介绍部分顶了,第二点是中南大学加黑加粗,第三点是建议加v详细交流
点赞 评论 收藏
分享
评论
2
2
分享

创作者周榜

更多
牛客网
牛客企业服务