WHAT - requestIdleCallback 介绍
文章目录
- 一、requestIdleCallback 是什么
- 二、基本用法
- 三、简单示例:避免主线程长时间阻塞
- 四、注意事项与兼容性
- 1. 兼容性
- 2. 超时兜底
- 五、与其他异步方式的区别
- 六、在 React 中的实际用法示例
- 总结
这是一个非常实用的性能优化 API.
一、requestIdleCallback 是什么
简单来说:
requestIdleCallback
允许你把不紧急的任务推迟到浏览器“空闲”时再执行,从而避免阻塞主线程,提升交互流畅度。
它的作用就是:
- 让渲染、交互优先执行
- 把一些“后台逻辑”放到主线程空闲的时候再慢慢处理
- 避免长任务导致 UI 卡顿、FID(First Input Delay)升高
二、基本用法
requestIdleCallback((deadline) => {while (deadline.timeRemaining() > 0 && tasks.length > 0) {const task = tasks.shift();doWork(task);}
});
deadline.timeRemaining()
:当前帧剩余的空闲时间(ms),浏览器会动态计算tasks
:你想在空闲时执行的任务队列
浏览器会在:
- 一帧渲染结束之后
- 事件循环空闲时
调用你注册的回调。
三、简单示例:避免主线程长时间阻塞
假设你原本这样写👇
// ❌ 这样会一次性占用主线程
const data = Array.from({ length: 100000 }, (_, i) => i);
data.forEach((item) => heavyCompute(item));
页面可能卡顿 200ms+。
改用 requestIdleCallback
分片执行
const data = Array.from({ length: 100000 }, (_, i) => i);function processChunk(deadline: IdleDeadline) {while (deadline.timeRemaining() > 0 && data.length > 0) {const item = data.pop();heavyCompute(item);}if (data.length > 0) {requestIdleCallback(processChunk);}
}requestIdleCallback(processChunk);
优势:
- 主线程不会被一次性大循环阻塞
- 页面仍然流畅
四、注意事项与兼容性
1. 兼容性
- 现代浏览器大多支持
- Safari 较老版本不支持(但可以用 polyfill)
推荐用 polyfill:
npm install requestidlecallback
import 'requestidlecallback';
2. 超时兜底
你也可以指定超时时间,防止任务永远不执行
requestIdleCallback(processChunk, { timeout: 2000 });
如果 2 秒内一直没有空闲时间,浏览器也会强制执行。
五、与其他异步方式的区别
方式 | 说明 | 适用场景 |
---|---|---|
setTimeout | 下一次事件循环执行 | 不保证不阻塞渲染 |
requestAnimationFrame | 下一帧渲染前执行(用于动画) | UI 动画相关 |
requestIdleCallback | 浏览器空闲时执行 | 非关键任务、后台任务 |
Web Worker | 另起线程执行 | 大计算量,和主线程隔离 |
requestIdleCallback
非常适合:
- 大量数据的分片处理
- 预加载资源
- 非关键性埋点/统计逻辑
- 延迟加载模块
六、在 React 中的实际用法示例
比如在一个 React 组件中渲染大量数据,你可以这样做
import { useEffect } from "react";function HeavyComponent() {useEffect(() => {const tasks = Array.from({ length: 100000 }, (_, i) => i);const processChunk = (deadline: IdleDeadline) => {while (deadline.timeRemaining() > 0 && tasks.length > 0) {const item = tasks.pop();heavyCompute(item);}if (tasks.length > 0) requestIdleCallback(processChunk);};requestIdleCallback(processChunk);}, []);return <div>页面不会被卡住了 🚀</div>;
}
这样:
- 页面渲染不会因为任务量大而卡死
- 你依然能在“后台”完成任务
总结
特性 | requestIdleCallback 的价值 |
---|---|
延迟执行非关键任务 | 减少主线程阻塞,改善交互体验 |
提升性能指标 | FID、TTI、CLS 改善 |
易于分片处理大任务 | 比一次性循环或 setTimeout 更优 |
可 polyfill | 不影响兼容性 |
实战建议:
- 把非首屏必要逻辑(数据预处理、统计、预加载)迁移到
requestIdleCallback
- 配合 Web Worker 使用效果更佳(Worker 处理大任务,Idle 处理非关键小任务)