它和 requestAnimationFrame 一样吗?
最初我以为这个函数就是和实现动画的 requestAnimationFrame 拥有相同的行为,因为它们的使用方法非常类似,但实际使用后发现它们的差别还是蛮大的。本文主要对这个神秘的函数进行一些说明和分析。
关于 requestAnimationFrame 相关内容看我之前文章《JavaScript 中 requestAnimationFrame 函数的简单介绍 用以实现流畅的动画》、《将 requestAnimationFrame 与 React Hooks 一起使用》
定义和用法
首先来看一下它的定义和用法,MDN 是这样定义它的:
这是一个实验中的功能,window.requestIdleCallback() 将一个(即将)在浏览器空闲时间执行的函数加入队列,这使得开发者在主事件循环中可以执行低优先级工作,而不影响对延迟敏感的事件,如动画和输入响应。
通过这个定义,我们发现它的执行时机在浏览器的“空闲”状态,那么怎样定义这个状态呢?
浏览器每一帧都需要完成这些任务:
-
处理用户交互 -
JS 执行 -
一帧的开始,处理视窗变化、页面滚动等 -
requestAnimationFrame(rAF) -
重排(layout) -
绘制(draw)
在这些步骤完成后,如果时间消耗还没超过 16ms,则浏览器还有余力去处理其他的任务,我们在 reqeustIdleCallback 中传入的回调将在此时执行;相反,如果时间消耗太大,则回调不执行,任务会顺延到下个帧浏览器空闲的时候再执行。而如果浏览器一直都很忙,那任务就会一再被推迟,很可能需要消耗大量时间后才得到执行。为了解决这个问题,可以在注册任务的时候提供一个 timeout 参数指定超时时间,在超时时间之内,该任务会被优先放在浏览器的执行队列中。
下面来看下它的用法:
// 这些只为了表明一些参数定义
type Dealine = {
timeRemaining: () => number // 当前剩余的可用时间
didTimeout: boolean // 是否超时
}
type Tick = (deadline: Dealine) => void;
type Options = { timeout: number }; // 可以提供一个超时时间,配合上面的 didTimeout 一起用
type RequestIdleCallback = (tick: Tick, options?: Options) => number // 类似于 rAF 返回一个句柄,可以把它传入 cancelIdleCallback 取消掉任务
一个常见的用法是,当有剩余时间或者 timeout 发生时执行一些任务,通常将任务保存在一个队列中便于进行调度。
// 待执行的任务队列
const taskQueue = [];
const tick = function(deadline) {
const remaining = deadline.timeRemaining();
while (remaining > 0 || didTimeout) {
// 如果超时,或者还有剩余执行时间,则执行这里的任务
// 执行任务队列中的任务
const currentTask = taskQueue.shift();
exec(currentTask);
}
// 再次注册,在下一个间隙继续执行 taskQueue 中的任务
requestIdleCallback(tick, { timeout: 500 });
};
requestIdleCallback(tick, { timeout: 500 });
reqeustIdleCallback 的执行行为
requestAnimationFrame 大家经常拿来实现动画,因为它是一个“靠谱的”函数,如果页面没有阻塞,那么这个函数每 16ms 左右调用一次;requestIdleCallback 则不同,它的执行间隔是不固定的,取决于浏览器此时正在执行的任务,下面举几个例子来看下。
我们简单地在页面中注册 requestIdleCallback,先不提供 timeout 参数
const tick = function(deadline) {
const remaining = deadline.timeRemaining();
if (remaining > 0) {
// do some stuff
}
requestIdleCallback(tick);
};
requestIdleCallback(tick);
场景一,页面中同时使用 requestAnimationFrame 函数循环注册一个事件,使页面发生重绘。
const cutiePie = document.querySelector('.cutie-pie');
const t = () => {
cutiePie.style.transform = `translate(${1 - Math.random() * 100}px, 0)`;
requestAnimationFrame(t);
}
requestAnimationFrame(t);

以上就是 window.reqeustIdleCallback 方法详解的详细内容,更多请关注www.mimiwuqi.com的其它相关文章!