前端任务调度实战:用 rAF + rIC 提升页面流畅度
在前端开发中,长任务或大量 DOM 操作会阻塞主线程,导致页面掉帧。通过 rAF 和 rIC,我们可以实现 高优先级任务与低优先级任务的合理调度。
一、场景设定
假设我们有两个任务:
- 动画任务(高优先级):持续更新 UI 元素位置
- 数据处理任务(低优先级):处理一堆数据、日志或缓存计算
我们希望:
- 动画流畅,不被阻塞
- 数据处理在浏览器空闲时执行,不影响渲染
二、动画任务(高优先级)- rAF
const box = document.getElementById('box');
let position = 0;
function animate() {
position += 2;
if (position > 300) position = 0;
box.style.transform = `translateX(${position}px)`;
requestAnimationFrame(animate);
}
// 启动动画
requestAnimationFrame(animate);
✅ 特点:
- 每帧调用一次动画函数
- 与浏览器渲染同步,保证平滑动画
三、后台数据任务(低优先级)- rIC
// 假设有一堆数据需要处理
let tasks = Array.from({ length: 1000 }, (_, i) => i + 1);
function processTasks(deadline) {
// 利用空闲时间处理任务
while (deadline.timeRemaining() > 0 && tasks.length > 0) {
const task = tasks.shift();
console.log('处理任务', task);
}
// 如果任务未完成,预约下一次空闲时间继续
if (tasks.length > 0) {
requestIdleCallback(processTasks);
}
}
// 启动空闲任务处理
requestIdleCallback(processTasks);
✅ 特点:
- 每次只处理当前空闲时间内的任务
- 大任务被分块执行,不阻塞动画
- 自动让出主线程,保证用户体验
四、综合示例:动画 + 数据处理
<div id="box" style="width:50px; height:50px; background:red; position:absolute;"></div>
// 动画任务
const box = document.getElementById('box');
let position = 0;
function animate() {
position += 2;
if (position > window.innerWidth - 50) position = 0;
box.style.transform = `translateX(${position}px)`;
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
// 后台数据处理任务
let tasks = Array.from({ length: 5000 }, (_, i) => i + 1);
function processTasks(deadline) {
while (deadline.timeRemaining() > 0 && tasks.length > 0) {
const task = tasks.shift();
// 模拟耗时计算
Math.sqrt(task * 12345);
}
if (tasks.length > 0) {
requestIdleCallback(processTasks);
}
}
requestIdleCallback(processTasks);
效果演示:
- 红色方块平滑移动,不掉帧
- 数据处理分块执行,不阻塞动画
五、实战技巧
- 区分任务优先级:UI 渲染、动画用 rAF;日志、缓存、后台计算用 rIC
- 任务分块:大任务拆分成小块,通过
timeRemaining()
控制执行量 - 兼容性考虑:rIC 在某些老版本浏览器不可用,可 fallback 到
setTimeout
const requestIdleCallbackSafe = window.requestIdleCallback || function(fn) {
return setTimeout(() => fn({ timeRemaining: () => 50 }), 0);
};
六、总结
- rAF:高优先级视觉任务,保证动画流畅
- rIC:低优先级后台任务,协作式调度,避免阻塞
- 组合使用可实现 性能和用户体验双赢
- 大任务分块处理 + 协作式调度 = 页面不卡顿