概念
window.requestIdleCallback()
方法插入一个函数,这个函数将在浏览器空闲时期被调用。这使开发者能够在主事件循环上执行后台和低优先级工作,而不会影响延迟关键事件,如动画和输入响应。函数一般会按先进先调用的顺序执行,然而,如果回调函数指定了执行超时时间timeout
,则有可能为了在超时前执行函数而打乱执行顺序。 你可以在空闲回调函数中调用requestIdleCallback()
,以便在下一次通过事件循环之前调度另一个回调。 var handle = window.requestIdleCallback(callback[, options]) 返回值 一个 ID,可以把它传入Window.cancelIdleCallback()
方法来结束回调。 参数callback
一个在事件循环空闲时即将被调用的函数的引用。函数会接收到一个名为IdleDeadline
的参数,这个参数可以获取当前空闲时间以及回调是否在超时时间前已经执行的状态。options
可选 包括可选的配置参数。具有如下属性:
timeout
:如果指定了 timeout,并且有一个正值,而回调在 timeout 毫秒过后还没有被调用,那么回调任务将放入事件循环中排队,即使这样做有可能对性能产生负面影响。
https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestIdleCallback
通俗点理解,requestIdleCallback 是为了让占用时间的任务放在一个事件循环中空闲时间去执行,而不影响主线程任务的执行,如用户交互、输入等,如果一个事件循环中空闲时间用完,则进入下次事件循环,继续在空闲时间执行。
demo
不使用 requestIdleCallback 直接执行一个耗时的循环,会导致另一个按钮点击后一直无法应用渲染,直到循环执行结束后,才可生效。
代码语言:javascript复制<!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>
</head>
<body>
<style>
#box {
padding: 20px;
background: palegoldenrod;
}
</style>
<!-- body -->
<div id="box"></div>
<button id="btn1">执行计算任务</button>
<button id="btn2">更改背景颜色</button>
<script>
const box = document.getElementById("box");
const btn1 = document.getElementById("btn1");
const btn2 = document.getElementById("btn2");
let number = 999999;
let value = 0;
function calc() {
while (number > 0) {
value = Math.random() < 0.5 ? Math.random() : Math.random();
console.log(value);
number--;
}
}
btn1.onclick = function () {
calc();
};
btn2.onclick = function () {
box.style.background = "green";
};
</script>
</body>
</html>
使用 requestIdleCallback 后,另一个按钮点击渲染的工作不受影响。
代码语言:javascript复制<style>
#box {
padding: 20px;
background: palegoldenrod;
}
</style>
<!-- body -->
<div id="box"></div>
<button id="btn1">执行计算任务</button>
<button id="btn2">更改背景颜色</button>
<script>
const box = document.getElementById("box");
const btn1 = document.getElementById("btn1");
const btn2 = document.getElementById("btn2");
let number = 999999;
let value = 0;
function calc(deadline) {
// deadline.timeRemaining() 等于 0 之后 循环就停止了,必须在 deadline.timeRemaining() 时间内执行,否则还是会阻塞,
while (number > 0 && deadline.timeRemaining() > 0) {
value = Math.random() < 0.5 ? Math.random() : Math.random();
number--;
}
// 所以这里需要再次调用,再下次主线程任务开始后寻找空闲时间来执行
requestIdleCallback(calc);
}
btn1.onclick = function () {
requestIdleCallback(calc);
};
btn2.onclick = function () {
box.style.background = "green";
};
</script>
参考:https://juejin.cn/post/6993973502852202503