微任务在当前宏任务结束后、下一个宏任务开始前立即清空执行,故Promise.then总比setTimeout先运行;宏任务典型有setTimeout、I/O、UI渲染等,微任务典型有Promise.then、queueMicrotask、MutationObserver、process.nextTick(Node.js特有,优先级最高)。

微任务在当前宏任务结束后、下一个宏任务开始前立即执行,所以 Promise.then 总是比 setTimeout 先运行。
宏任务和微任务的典型代表有哪些?
区分二者的关键不是“谁更小”,而是浏览器/Node.js引擎定义的**任务分类规则**:
- 宏任务(Macrotask):
setTimeout、setInterval、setImmediate(Node.js)、I/O 回调、UI 渲染(浏览器)、postMessage - 微任务(Microtask):
Promise.then/catch/finally、queueMicrotask、MutationObserver回调、process.nextTick(Node.js,优先级高于 Promise)
注意:process.nextTick 是 Node.js 特有,它不属于标准微任务队列,但执行时机比 Promise 更早——它会在当前操作完成后、任何微任务之前执行。
事件循环中它们的执行顺序到底是怎样的?
一次完整的事件循环流程是:
立即学习“Java免费学习笔记(深入)”;
- 执行一个宏任务(比如主线程脚本、或某个
setTimeout回调) - 执行过程中遇到
Promise,其then被推入微任务队列;遇到setTimeout,其回调被推入宏任务队列 - 当前宏任务执行完,**立刻清空整个微任务队列**(所有已排队的微任务依次执行,且新加入的微任务也会在这轮被处理)
- 然后才从宏任务队列取下一个任务(可能是渲染、也可能是另一个
setTimeout)
这意味着:哪怕你在微任务里又创建了新的微任务,它也会被本轮执行掉,不会等到下一轮宏任务之后。
console.log(1); setTimeout(() => console.log(2), 0); Promise.resolve().then(() => console.log(3)); Promise.resolve().then(() => console.log(4)); console.log(5); // 输出:1 → 5 → 3 → 4 → 2
为什么 async/await 看起来像同步,实际还是微任务?
async 函数返回的是 Promise,await 后面的表达式一旦 resolve,后续代码会被包装进 Promise.then —— 所以它本质仍是微任务调度。
-
await不会阻塞线程,只是让出控制权,等 Promise settled 后再把后续逻辑排进微任务队列 - 多个
await链式调用,每一步 resolve 后都会触发一次微任务排队 - 如果
await的是普通值(非 Promise),V8 会自动包装成Promise.resolve(value),仍走微任务流程
console.log('start');
async function foo() {
console.log('before await');
await Promise.resolve();
console.log('after await');
}
foo();
console.log('end');
// 输出:start → before await → end → after await
真正容易被忽略的是:微任务队列在每次宏任务后被**完全清空**,而不是只执行一个。这个“清空”行为会让嵌套的 Promise.then 或连续的 queueMicrotask 表现出极强的连续性,甚至可能引发栈溢出风险(比如递归调用 queueMicrotask 却不设退出条件)。










