requestIdleCallback
是一个浏览器提供的 API,用于在主线程空闲时执行低优先级的操作,而不会阻塞主线程的执行。这对于执行一些非紧急的任务(如统计、数据预处理等)非常有用。
以下是 requestIdleCallback
的基本使用方法:
- 定义一个回调函数:这个函数将在主线程空闲时执行。
- 调用
requestIdleCallback
并传入回调函数:这个方法会返回一个唯一的 ID,用于后续的取消操作。 - (可选)使用
cancelIdleCallback
取消回调:如果需要取消已经排期的回调,可以使用这个方法。
示例代码
// 定义一个回调函数
function myIdleTask(deadline) {
// 检查是否有剩余时间
while ((deadline.timeRemaining() > 0 || deadline.didTimeout) && tasks.length > 0) {
doOneTask();
}
// 如果还有任务未完成,继续请求空闲时间
if (tasks.length > 0) {
requestIdleCallback(myIdleTask);
}
}
// 调用 requestIdleCallback 并传入回调函数
let idleCallbackId = requestIdleCallback(myIdleTask);
// 取消回调(可选)
cancelIdleCallback(idleCallbackId);
参数说明
-
回调函数:接受一个
deadline
参数,该参数是一个对象,包含两个属性:timeRemaining()
:返回当前帧还剩多少时间(毫秒)。didTimeout
:一个布尔值,表示是否因为超时执行了回调。
-
options(可选):可以传入一个配置对象,包含一个
timeout
属性,表示回调函数的最大等待时间(毫秒)。如果设置了timeout
,即使主线程没有空闲时间,回调函数也会在超时后执行。
注意事项
requestIdleCallback
在某些浏览器中可能不可用,因此建议使用 polyfill 以确保兼容性。- 使用
requestIdleCallback
时,不要依赖它来执行关键任务,因为它可能会在主线程非常繁忙时被推迟执行。
Polyfill
如果需要兼容不支持 requestIdleCallback
的浏览器,可以使用以下 polyfill:
if (!window.requestIdleCallback) {
window.requestIdleCallback = function (callback, options) {
const { timeout } = options || {};
const startTime = Date.now();
return setTimeout(function () {
callback({
timeRemaining: function () {
return Math.max(0, timeout - (Date.now() - startTime));
},
didTimeout: Boolean(timeout) && Date.now() - startTime >= timeout
});
}, 1);
};
}
if (!window.cancelIdleCallback) {
window.cancelIdleCallback = function (id) {
clearTimeout(id);
};
}
通过这种方式,你可以确保 requestIdleCallback
在所有浏览器中都能正常工作。
对于单页引用可能需要手动关闭requestIdleCallback
requestIdleCallback
本身不会自动关闭或取消已经排期的回调。如果你不再需要执行某个回调,或者组件被卸载了,你需要手动取消该回调。这可以通过 cancelIdleCallback
方法来实现。
以下是一个示例,展示了如何在组件卸载时取消 requestIdleCallback
:
import { onMounted, onUnmounted, ref } from 'vue';
export default {
setup() {
const idleCallbackId = ref(null);
function idleTask(deadline) {
// 执行一些任务...
console.log('Executing idle task');
// 如果需要继续执行任务,可以再次请求空闲时间
idleCallbackId.value = requestIdleCallback(idleTask);
}
onMounted(() => {
// 组件挂载时请求空闲时间
idleCallbackId.value = requestIdleCallback(idleTask);
});
onUnmounted(() => {
// 组件卸载时取消空闲回调
if (idleCallbackId.value !== null) {
cancelIdleCallback(idleCallbackId.value);
}
});
return {
idleCallbackId
};
}
};
在这个示例中,idleCallbackId
保存了 requestIdleCallback
返回的 ID。当组件卸载时,通过 cancelIdleCallback
取消回调,以防止组件卸载后仍然执行回调函数。
总结
虽然 requestIdleCallback
不会自动关闭,但在某些情况下(如组件卸载、任务完成等),你需要手动取消回调,以避免不必要的执行和可能的内存泄漏。使用 cancelIdleCallback
可以轻松实现这一点。
如果被执行过的requestIdleCallback,不需要手动关闭
requestIdleCallback
的回调函数在执行完毕后,如果没有再次调用 requestIdleCallback
来安排下一次执行,那么它就不需要被关闭。换句话说,当 requestIdleCallback
的回调函数执行完毕后,它自然就结束了,不需要额外的关闭操作。
但是,如果你在回调函数内部再次调用了 requestIdleCallback
来安排下一次执行,那么你需要确保在适当的时候(例如组件卸载或任务完成时)使用 cancelIdleCallback
来取消未来的回调。
示例
以下是一个示例,展示了如何根据任务列表来决定是否需要再次调用 requestIdleCallback
:
// 定义一个任务列表
const tasks = [
() => console.log('Task 1 completed'),
() => console.log('Task 2 completed'),
() => console.log('Task 3 completed'),
// 添加更多任务...
];
// 定义一个回调函数,用于在空闲时间执行任务
function idleTask(deadline) {
// 检查是否有剩余时间
while ((deadline.timeRemaining() > 0 || deadline.didTimeout) && tasks.length > 0) {
// 执行任务
const task = tasks.shift();
task();
}
// 如果还有任务未完成,继续请求空闲时间
if (tasks.length > 0) {
requestIdleCallback(idleTask);
}
}
// 请求空闲时间并传入回调函数
requestIdleCallback(idleTask);
在这个示例中,idleTask
回调函数会在每次执行时检查任务列表。如果任务列表中还有任务,它会再次调用 requestIdleCallback
来安排下一次执行。如果任务列表为空,回调函数自然结束,不需要额外的关闭操作。
总结
- 不需要关闭:如果
requestIdleCallback
的回调函数执行完毕后没有再次调用requestIdleCallback
,那么它就不需要被关闭。 - 需要关闭:如果在回调函数内部再次调用了
requestIdleCallback
,那么在适当的时候(如组件卸载或任务完成时)需要使用cancelIdleCallback
来取消未来的回调。