2020-07-23 20:30:08
requestIdleCallback在浏览器事件循环中的作用是利用浏览器空闲时间执行低优先级任务,避免主线程阻塞,确保页面流畅响应。
允许开发者将非关键任务(如数据上报、资源预加载)推迟到主线程空闲时执行。
回调函数接收IdleDeadline对象,通过timeRemaining()判断剩余空闲时间,确保任务分片执行,避免超时。
支持timeout参数,保障任务在指定时间内执行(即使主线程未空闲),防止任务被无限延迟。

解决的问题:
主线程阻塞导致的UI卡顿:通过将非必要任务推迟到空闲时执行,确保动画流畅、用户输入响应及时。
资源利用率低下:利用帧与帧之间的碎片时间执行任务,提升CPU和GPU的利用率。
任务优先级管理混乱:提供明确的机制调度低优先级任务,区分“现在必须做”和“有空再做”的任务。
与requestAnimationFrame的区别:
requestAnimationFrame(rAF):
用于优化动画和视觉更新,执行时机与浏览器刷新率同步(高优先级)。
适用于DOM元素位移、缩放、透明度变化等直接影响视觉的操作。
requestIdleCallback(rIC):
用于利用浏览器空闲时间执行低优先级任务,执行时机不保证(低优先级)。
适用于数据上报、资源预加载、后台同步等不影响UI的任务。

使用场景:
数据上报与分析:批量发送用户行为数据、错误日志,减少对用户操作的干扰。
非关键资源预加载:利用空闲时间加载图片、字体、JS模块等非首屏资源。
后台数据同步:在空闲时进行数据同步,避免阻塞用户操作。
复杂计算:分片执行排序、过滤、聚合等不影响UI的计算任务。
组件非关键初始化:推迟富文本编辑器的拼写检查、高级格式化工具等非核心功能初始化。
最佳实践:
检查deadline.timeRemaining():在回调中不断检查剩余时间,时间不足时停止当前任务并重新调度。function processQueue(deadline) { while (deadline.timeRemaining() > 0 && taskQueue.length > 0) { const task = taskQueue.shift(); executeTask(task); } if (taskQueue.length > 0) { requestIdleCallback(processQueue); }}
设置timeout选项:确保任务在指定时间内执行,避免无限延迟。requestIdleCallback(myTask, { timeout: 2000 });
避免DOM操作:DOM操作可能触发布局和重绘,抵消requestIdleCallback的优势。如需修改DOM,可结合requestAnimationFrame或确保操作微小。
处理兼容性:通过降级方案(如setTimeout)兼容旧版浏览器。window.requestIdleCallback = window.requestIdleCallback || function(cb) { var start = Date.now(); return setTimeout(function() { cb({ didTimeout: false, timeRemaining: function() { return Math.max(0, 50 - (Date.now() - start)); } }); }, 1);};
任务分片:将耗时任务分解为小块,每次处理一部分后重新调度。

requestIdleCallback通过协作式调度,在不牺牲用户体验的前提下提升Web应用性能。
适用于低优先级任务,与requestAnimationFrame互补,共同构建高性能应用。