在 javascript 的事件循环中,宏任务与微任务的执行顺序由当前调用栈清空后的调度机制决定:每次宏任务(如 settimeout)执行完毕后,引擎会立即清空所有待处理的微任务队列(如 promise.then),直到微任务队列为空才进入下一轮宏任务。这意味着微任务总是优先于后续的宏任务执行,且在同一轮事件循环中,微任务的执行顺序严格遵循注册顺序。

为什么 Promise 回调比 setTimeout 先执行
因为 Promise.then 的回调被归类为微任务,而 setTimeout 的回调是宏任务。当代码同步执行到 new Promise 时,其构造函数内的逻辑是同步执行的,但 .then 注册的回调会被放入微任务队列;而 setTimeout 即使延迟为 0ms,其回调也会被放入宏任务队列。由于事件循环规定在一次宏任务结束后必须处理完所有微任务,所以微任务中的输出会先于宏任务出现。

console.log('1');
setTimeout(function() {
console.log('2');
}, 0);
new Promise(function(resolve) {
console.log('3');
resolve();
}).then(function() {
console.log('4');
});
console.log('5');
预期输出结果:
1
3
5
4
2
多个微任务之间的执行顺序如何确定
同一轮事件循环中产生的多个微任务,严格按照它们被加入队列的先后顺序依次执行。例如,如果在第一个 Promise.then 中又创建了一个新的 Promise 并注册了 .then,这个新的微任务会被追加到当前微任务队列的末尾,并在当前所有已存在的微任务处理完毕后执行,而不是插入到中间。这种 FIFO(先进先出)的特性保证了微任务执行的确定性。

Promise.resolve().then(function() {
console.log('A');
Promise.resolve().then(function() {
console.log('B');
});
console.log('C');
});
console.log('D');
预期输出结果:
D
A
C
B
如果微任务中抛出异常会发生什么
如果微任务在执行过程中抛出未捕获的异常,该异常会中断当前微任务队列的后续执行,但不会阻塞事件循环本身。引擎会记录错误(通常在控制台打印),然后继续处理剩余的宏任务。这与同步代码不同,同步代码中异常会直接跳出当前作用域,而微任务中的异常仅影响当前微任务及其后同级的微任务,前序已执行的微任务不受影响。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











