基于这个关于JS中微任务队列检查点的公认答案并更多地查找这个概念,我开始理解以下内容:
微任务队列检查点发生在事件循环中的这些点:
为了通过示例理解这一点,我尝试了以下代码示例:
setTimeout(() => {
console.log('timeout1');
}, 3000);
setTimeout(() => {
console.log('timeout2');
}, 3000);
let promise = new Promise(function (resolve, reject) {
setTimeout(() => resolve('promise!'), 3000);
});
promise.then(
(result) => console.log(result),
(err) => console.log(err)
);
根据JS中事件循环的概念,setTimeouts函数会在指定的时间过去后被推送到宏任务队列中。因此,所有三个 setTimeout 任务都应该在 3 秒过去后被推送到宏任务队列中。另一方面,传递给 Promise 的 .then() 的函数应该被推送到微任务队列。对于上面的代码,在后续循环开始时,应该运行第一个被推送到宏任务队列的 setTimeout 任务来打印“timeout1”。
根据我上面提供的微任务队列检查点概念,此后应该会出现检查点,并且微任务队列中的打印函数应该打印“promise!”。
最后,应打印宏任务队列“timeout2”上的第二个宏任务。
但是,在 Chrome 和 Firefox(最新版本)的控制台上,并通过我的机器上的 Node v16.14.0 运行代码,我发现打印的顺序是:
timeout1
timeout2
promise!
微任务队列检查点行为是否无法保证?如果是的话,我的评估是否在其他地方出错了?
将记录
"promise!"
的微任务将在从 Promise 构造函数调度的计时器任务执行后立即执行,但其他两个计时器任务是在该任务之前调度的,因此它们首先执行。事实上,从 Promise 的决议中排队的微任务在这里并不重要:
setTimeout(() => {
console.log('timeout1');
}, 3000);
setTimeout(() => {
console.log('timeout2');
}, 3000);
let promise = new Promise(function (resolve, reject) {
setTimeout(() => {
resolve('promise!');
// 'timeout3' will be logged before 'promise!' but after both other timeouts
// because these got queued before us.
console.log('timeout3');
}, 3000);
});
promise.then(
(result) => console.log(result),
(err) => console.log(err)
);