JavaScript 里 await 等待 Promise 时的微任务调度细节

作者:袖梨 2026-07-08
await触发的微任务在当前宏任务结束前入队,但需等该宏任务彻底完成后才执行;若await右侧Promise已settled,则立即入队,否则待其状态变更后入队,且与Promise.then同优先级、同微任务队列。

await 不是简单“暂停函数”,而是把后续代码包装成微任务,在当前宏任务末尾排队执行。

await 触发的微任务何时入队?

当执行到 await promise 时:

  • 如果 promise 已 fulfilled 或 rejected,JavaScript 引擎立即把 await 后面的语句(即 async 函数中接下来的代码)包装成一个微任务,加入微任务队列;
  • 如果 promise 还处于 pending,则先挂起 async 函数,等 promise 状态变更后,再将后续逻辑作为微任务入队;
  • 注意:这个微任务是在 当前正在执行的宏任务结束前 就已入队,但要等到当前宏任务彻底完成、控制权交还事件循环后才执行。

await 和 Promise.then 的微任务优先级相同

await 后续代码和 Promise.prototype.then 回调都属于微任务,进入同一微任务队列,按入队顺序执行(FIFO):

  • 例如:await Promise.resolve(); console.log('a');Promise.resolve().then(() => console.log('b')) 中,'a' 和 'b' 的打印顺序取决于谁先入队;
  • 若两者在同一宏任务中,await 后续代码一定早于 then 回调入队(因为 await 表达式求值在前),所以通常先执行 'a';
  • 但如果 then 是在 await 暂停期间被 resolve 触发(比如异步 resolve),那它可能更早入队。

await 挂起不阻塞事件循环

async 函数遇到 await 时会返回一个 pending 的 Promise 并立即让出线程,当前宏任务继续向下执行或结束:

立即学习“Java免费学习笔记(深入)”;

  • 后续代码不会同步执行,也不会占用调用栈;
  • 引擎记录 async 函数的上下文(如变量环境、执行点),等对应 promise settle 后,再用该上下文恢复执行;
  • 这正是 async/await 能避免回调地狱却保持非阻塞特性的核心机制。

常见误区:await 不等于 setTimeout(0)

setTimeout(fn, 0) 推送的是宏任务,而 await 推送的是微任务:

  • 微任务总在当前宏任务结束前全部清空,宏任务则要等下一轮事件循环;
  • 因此 await Promise.resolve(); console.log('micro'); 一定早于 setTimeout(() => console.log('macro'), 0); 打印;
  • 即使 Promise 是同步 resolve 的,await 后的代码仍要等本轮宏任务结束,但仍在 setTimeout 之前运行。

理解 await 的微任务调度,关键在于看清它如何与事件循环协作——不是“等待”,而是“安排后续工作稍后执行”。

相关文章

精彩推荐