在 JavaScript 中,Promise 的回调是通过微任务队列(Microtask Queue)来处理的,这与常规的异步任务(如 setTimeout、setInterval 等)使用的宏任务队列(Macrotask Queue/Task Queue)不同。
微任务(Microtask):
.then()
、.catch()
、.finally()
回调宏任务(Macrotask):
JavaScript 事件循环(Event Loop)的执行顺序规则:
console.log('Script start');
setTimeout(() => {
console.log('setTimeout');
}, 0);
Promise.resolve()
.then(() => {
console.log('Promise 1');
})
.then(() => {
console.log('Promise 2');
});
console.log('Script end');
输出顺序:
Script start
Script end
Promise 1
Promise 2
setTimeout
微任务会在当前事件循环中全部执行完毕,即使是在微任务中产生的新的微任务:
Promise.resolve()
.then(() => {
console.log('Promise 1');
return Promise.resolve();
})
.then(() => {
console.log('Promise 2');
queueMicrotask(() => {
console.log('queueMicrotask');
});
})
.then(() => {
console.log('Promise 3');
});
输出顺序:
Promise 1
Promise 2
queueMicrotask
Promise 3
理解微任务对于控制代码执行顺序非常重要,特别是在处理异步操作时:
let button = document.getElementById('button');
button.addEventListener('click', () => {
Promise.resolve().then(() => console.log('Microtask 1'));
console.log('Listener 1');
});
button.addEventListener('click', () => {
Promise.resolve().then(() => console.log('Microtask 2'));
console.log('Listener 2');
});
button.click();
输出顺序:
Listener 1
Listener 2
Microtask 1
Microtask 2
queueMicrotask()
可以直接将函数加入微任务队列理解微任务机制对于编写高效、可预测的异步 JavaScript 代码至关重要。