跳到主要内容

认识

2024年03月06日
柏拉文
越努力,越幸运

一、认识


window.requestIdleCallback() 方法插入一个函数,这个函数将在浏览器空闲时期被调用。这使开发者能够在主事件循环上执行后台和低优先级工作,而不会影响延迟关键事件,如动画和输入响应。函数一般会按先进先调用的顺序执行,然而,如果回调函数指定了执行超时时间 timeout,则有可能为了在超时前执行函数而打乱执行顺序。

window.requestIdleCallback() 底层是在一轮事件循环的最后执行。此时, 浏览器绘制完成, 判断执行栈微任务队列是否都为空,如果是的话,则进行 Idle 空闲周期的算法,判断是否要执行 requestIdleCallback 的回调函数

二、语法


const callbackID = requestIdleCallback(callback)

const callbackID = requestIdleCallback(callback, options)
  • callback: 一个在事件循环空闲时即将被调用的函数的引用。函数会接收到一个名为 IdleDeadline 的参数, IdleDeadline 它提供了 timeRemaining() 方法,用来判断用户代理预计还剩余多少闲置时间, 以及 didTimeout属性,用来判断当前的回调函数是否因超时而被执行。

    • IdleDeadline.didTimeout: 一个布尔值,如果回调是因为超过了设置的超时时间而被执行的,则其值为 true

    • IdleDeadline.timeRemaining(): 返回一个 DOMHighResTimeStamp,其为浮点数,用来表示当前闲置周期的预估剩余毫秒数。如果闲置期已经结束,则其值为 0。你的回调函数可以重复调用该函数,以判断目前是否有足够的时间来执行更多的任务。

  • options: 包括可选的配置参数。具有如下属性:

    • timeout: 果指定了 timeout,并且有一个正值,而回调在 timeout 毫秒过后还没有被调用,那么回调任务将放入事件循环中排队,即使这样做有可能对性能产生负面影响。手动设置 timeout 参数可能会导致 app 无响应, 影响用户体验, 所以尽量让浏览器自行来计算决定.
  • callbackID: 一个 ID,可以把它传入 Window.cancelIdleCallback() 方法来结束回调。

三、用法


3.1 空闲时间

class Scheduler {
constructor() {
this.tasks = [];
this.callbackID = null;
}

add(task) {
this.tasks.push(task);
if (!this.callbackID) {
this.start();
}
}

start() {
this.callbackID = window.requestIdleCallback((deadline) => {
while ((deadline.timeRemaining() > 0) && this.tasks.length > 0) {
const task = this.tasks.shift();
task();
}
if (this.tasks.length > 0) {
this.start();
} else {
window.cancelIdleCallback(this.callbackID);
this.callbackID = null;
}
});
}
}

3.2 任务超时

class Scheduler {
constructor() {
this.tasks = [];
this.callbackID = null;
}

add(task) {
this.tasks.push(task);
if (!this.callbackID) {
this.start();
}
}

start() {
this.callbackID = window.requestIdleCallback((deadline) => {
while ((deadline.didTimeout) && this.tasks.length > 0) {
const task = this.tasks.shift();
task();
}
if (this.tasks.length > 0) {
this.start();
} else {
window.cancelIdleCallback(this.callbackID);
this.callbackID = null;
}
});
}
}

3.3 空闲时间或任务超时

class Scheduler {
constructor() {
this.tasks = [];
this.callbackID = null;
}

add(task) {
this.tasks.push(task);
if (!this.callbackID) {
this.start();
}
}

start() {
this.callbackID = window.requestIdleCallback((deadline) => {
while ((deadline.timeRemaining() > 0 || deadline.didTimeout) && this.tasks.length > 0) {
const task = this.tasks.shift();
task();
}
if (this.tasks.length > 0) {
this.start();
} else {
window.cancelIdleCallback(this.callbackID);
this.callbackID = null;
}
});
}
}