在 javascript 事件循环中,微任务(如 promise.then、mutationobserver)会在当前宏任务(如 settimeout、setinterval)的回调函数执行完毕后立即执行。具体做法是:在宏任务的回调函数中通过 promise.resolve().then() 或 queuemicrotask() 注册微任务,这些任务会被放入微任务队列,并在当前调用栈清空后、下一个宏任务开始前被依次处理。

如何确保代码在 setTimeout 回调后同步执行
要让一段逻辑在 setTimeout 的回调执行后立即运行,可以在该回调内部使用 Promise.resolve().then() 将逻辑包装为微任务。这样,当 setTimeout 的回调执行完毕,JavaScript 引擎会检查微任务队列并执行其中的任务,然后再继续处理其他宏任务。

console.log('1. 同步代码');
setTimeout(() => {
console.log('2. setTimeout 回调开始');
Promise.resolve().then(() => {
console.log('3. 微任务 (Promise)');
});
queueMicrotask(() => {
console.log('4. 微任务 (queueMicrotask)');
});
console.log('5. setTimeout 回调结束');
}, 0);
console.log('6. 同步代码结束');预期输出顺序为:
1. 同步代码
6. 同步代码结束
2. setTimeout 回调开始
5. setTimeout 回调结束
3. 微任务 (Promise)
4. 微任务 (queueMicrotask)
立即学习“Java免费学习笔记(深入)”;
为什么微任务比下一个宏任务先执行
微任务之所以在下一个宏任务之前执行,是因为事件循环的设计规范规定:每次宏任务执行完后,必须清空整个微任务队列,然后才能进入下一个宏任务。这种机制保证了高优先级的异步操作(如 DOM 更新、状态同步)能尽快得到处理,避免页面闪烁或数据不一致。

// 对比宏任务与微任务的执行时机
console.log('Start');
setTimeout(() => {
console.log('Timeout 1');
}, 0);
new Promise(resolve => {
console.log('Promise executor');
resolve();
}).then(() => {
console.log('Promise then 1');
});
setTimeout(() => {
console.log('Timeout 2');
}, 0);
console.log('End');预期输出顺序为:
Start
Promise executor
End
Promise then 1
Timeout 1
Timeout 2
基于 Promise.then 回调中嵌套微任务的具体问题
如果在 Promise.then 的回调中再次创建新的微任务,这些新微任务会被追加到当前微任务队列的末尾,并在当前所有已存在的微任务执行完毕后继续执行。这意味着微任务可以无限递归地触发后续微任务,直到队列为空。


















