在 JavaScript 中,任务调度机制分为宏任务(macro task)和微任务(micro task)。它们的执行顺序和调度方式有所不同。
宏任务(Macro Task)
宏任务是指那些在事件循环的每个循环迭代中执行的任务。常见的宏任务包括:
setTimeoutsetIntervalsetImmediate(Node.js 环境)- I/O 操作
- UI 渲染
微任务(Micro Task)
微任务是在当前宏任务执行结束后立即执行的任务。常见的微任务包括:
执行顺序
- 执行一个宏任务(从事件队列中取一个)。
- 执行过程中如果遇到微任务,就将它添加到微任务队列。
- 当前宏任务执行完毕后,立即执行所有微任务(依次执行微任务队列中的任务)。
- 执行完所有微任务后,再从事件队列中取下一个宏任务,进入下一个循环。
示例
以下是一个简单的示例,展示了宏任务和微任务的执行顺序:
console.log('script start');
setTimeout(() => {
console.log('setTimeout');
}, 0);
Promise.resolve().then(() => {
console.log('promise1');
}).then(() => {
console.log('promise2');
});
console.log('script end');
输出顺序
script startscript endpromise1promise2setTimeout
解释
- 首先执行同步代码,输出
script start和script end。 setTimeout是一个宏任务,它会在事件循环的下一个迭代中执行。Promise的回调是微任务,会在当前宏任务执行完毕后立即执行。- 因此,
promise1和promise2会在setTimeout之前执行。
结合代码示例
下面这段代码中,flushJob 函数使用了 Promise.resolve().then(...),这意味着 jobQueue 中的任务会作为微任务执行:
function flushJob() {
if (isFlushing) return
isFlushing = true
p.then(() => { // 微任务
jobQueue.forEach(job => job())
}).finally(() => {
isFlushing = false
})
}
这确保了 jobQueue 中的任务会在当前宏任务执行完毕后立即执行,而不会等到下一个宏任务。