requestIdleCallback
是一个用于在空闲时执行任务的 JavaScript API。在浏览器中,当主线程空闲时,通常会用于处理用户交互和渲染,而 requestIdleCallback
可以在主线程空闲时执行一些低优先级的任务,以避免阻塞用户交互和渲染。
语法
requestIdleCallback(callback)
requestIdleCallback(callback, options)
- 参数
-
callback
一个在事件循环空闲时即将被调用的函数的引用。函数会接收到一个名为IdleDeadline
的参数,这个参数可以获取当前空闲时间以及回调是否在超时时间前已经执行的状态。 -
options (可选):包括可选的配置参数。具有如下属性:
- timeout:如果指定了 timeout,并且有一个正值,而回调在 timeout 毫秒过后还没有被调用,那么回调任务将放入事件循环中排队,即使这样做有可能对性能产生负面影响。
-
- 返回值
一个 ID,可以把它传入Window.cancelIdleCallback()
方法来结束回调。
requestIdleCallback
的使用方法与 setTimeout
类似,只是它在浏览器处于空闲状态时才会执行回调函数。回调函数接收一个 IdleDeadline 对象,可以通过该对象判断当前剩余的空闲时间,从而在有限的时间内执行适当的任务。
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.ball {
width: 100px;
height: 100px;
border-radius: 50%;
background-color: #f00;
position: absolute;
left: 0;
top: 50px;
animation: move 10s infinite alternate;
}
@keyframes move {
0% {
left: 0px;
}
100% {
left: 500px;
}
}
</style>
</head>
<body>
<div class="ball"></div>
<script>
function delay(duration) {
const start = Date.now();
while (Date.now() - start < duration) {}
}
const taskList = []; // 存放任务的队列
// 推入任务
for (let i = 1; i <= 10; i++) {
taskList.push(() => {
delay(10);
console.log(`执行任务${i}`);
});
}
// 接下来我们想要执行任务,每一帧渲染完毕后有剩余时间
// 如果时间充足,我们就执行任务
// 如果时间不充足,那么就在下一帧渲染后再接着执行
function callback(IdleDeadline) {
// 执行任务
console.log(
"当前帧绘制完毕后所剩余的时间:",
IdleDeadline.timeRemaining()
);
while (IdleDeadline.timeRemaining() > 0 && taskList.length) {
// 还有剩余时间,并且任务列表还有任务
const task = taskList.shift();
task();
}
// 退出上面的 while 后,有一种情况是当前帧的时间不够了,但是任务列表中还有剩余任务
if (taskList.length) {
// 那么我们就在下一帧空闲时间再继续执行任务
window.requestIdleCallback(callback);
}
}
window.requestIdleCallback(callback);
</script>
</body>
</html>
通过示例我们发现,每一帧绘制的时间约为 16.66ms,但是如果屏幕没有刷新,那么浏览器会安排长度为 50ms 左右的空闲时间。
为什么是50ms?
根据研究报告表明,用户操作之后,100ms以内的响应给用户的感觉都是瞬间发生,也就是说不会感受到延迟感,因此将空闲时间设置为 50,浏览器依然还剩下 50ms 可以处理用户的操作响应,不会让用户感到延迟。
IdleDeadline
IdleDeadline
是指在浏览器中执行 JavaScript 代码时的一个时间截点,可以用来优化代码的执行。当浏览器空闲时,即没有用户交互或其他任务需要执行时,浏览器会将剩余的时间片分配给 JavaScript 代码执行。在执行每个时间片之前,浏览器都会检查当前的时间是否超过了 IdleDeadline
,如果超过了,浏览器就会停止执行 JavaScript 代码,以保证用户体验的流畅性。
使用 IdleDeadline
可以将耗时较长的任务分解为多个小任务,每次在空闲时执行一部分,以避免长时间的阻塞。这样可以使页面在执行 JavaScript 代码的同时仍然能够保持响应,并且增加了用户的交互性。
-
属性
IdleDeadline.didTimeout
(只读):布尔值,如果回调是因为超过了设置的超时时间而被执行的,则其值为 true
-
方法
IdleDeadline.timeRemaining()
:返回一个 DOMHighResTimeStamp,其为浮点数,用来表示当前闲置周期的预估剩余毫秒数。如果闲置期已经结束,则其值为 0。你的回调函数可以重复调用该函数,以判断目前是否有足够的时间来执行更多的任务。
cancelIdleCallback
window.cancelIdleCallback()
方法用于取消之前调用window.requestIdleCallback()
的回调。
语法
cancelIdleCallback(handle)
- 参数
- handle: 调用
window.requestIdleCallback()
时返回的 ID.
- handle: 调用
注意
需要注意的是,requestIdleCallback
并不是一个跨浏览器兼容的 API,所以在使用前需要检测当前浏览器是否支持该 API,并适当提供兼容方案。如果浏览器不支持该 API,可以使用 setTimeout
或 requestAnimationFrame
来代替。