最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
JavaScript 里 await 等待 Promise 时的微任务调度细节
时间:2026-07-08 11:52:45 编辑:袖梨 来源:一聚教程网
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 的微任务调度,关键在于看清它如何与事件循环协作——不是“等待”,而是“安排后续工作稍后执行”。