众所周知 js 在运行完同步逻辑后,反复轮流遍历微任务队列和宏任务队列。
这两个队列在遍历时有所不同:
微任务队列在遍历时如果向其队尾加入新任务,新任务会加入本轮遍历!
而宏任务队列在遍历时如果向其队尾加入新任务,新任务不加入本轮遍历,直到下一轮才可以遍历!
!!!还有一件事,微任务队列的反复遍历是反复从队首往队尾遍历,直到队列为空
!!!还有一件事,微任务队列中 promise.then 和 catch 的是否调用取决于本次遍历刚刚开始时的 promise 对象状态,而不是在微任务队列遍历过程中实时更新
下面是简单的验证过程,不是证明:
// 这是对微任务队列不分层遍历的验证
Promise.resolve().then(() => {
console.log(1)
setTimeout(() => {
console.log(2)
}, 0)
Promise.resolve().then(() => {
console.log(3)
})
})
// 实际运行结果是:1 3 2
// 下面的过程每个步骤用两个数组分别表示宏、微任务队列,用'^'符号表示正在处理的任务
// 同步过程:[][]->[][1]
// 第一次遍历微任务队列:[][^1]->输出1->[][]->[2][]->[2][^3]->输出3->[2][]
// 第一次遍历宏任务队列:[^2][]->输出2->[][]
// 该结果符合实际结果,而如果不是如此那么输出结果应该是:1 2 3
// 这是对宏任务分层遍历的验证
setTimeout(/*func1*/() => {
console.log(1)
Promise.resolve().then(() => {
console.log(2)
})
setTimeout(() => {
console.log(3)
}, 0)
}, 0)
// 实际运行结果是:1 2 3
// 同步过程:[][]->[func1][]
// 第一次遍历微任务队列:(null)
// 第一次遍历宏任务队列:[^func1][]->输出1->[^func1][2]->[^func1,3][2]->[3][2]
// 第二次遍历微任务队列:[3][^2]->输出2->[3][]
// 第二次遍历宏任务队列:[^3][]->输出3->[][]
// 该结果符合实际结果,而如果不是如此那么输出结果应该是:1 3 2