await 后多个 promise 是按顺序逐个触发并注册微任务,而非并发注册;每个 await 暂停函数执行,待当前 promise settled 后才解析下一行,因此微任务分批延迟入队。

await 后面跟多个 Promise(比如 await p1; await p2; await p3;),它们不是“同时入队”,而是**按执行顺序逐个触发、逐个入队微任务**,且每个 await 都会暂停当前 async 函数的执行,直到对应 Promise settled 后才继续下一行——这决定了微任务队列的实际填充节奏和执行时机。
await 是逐行阻塞的,不是并发注册微任务
很多人误以为写多个 await 就像 Promise.all 那样并行启动所有 Promise,其实不然。JavaScript 引擎在遇到 await p 时:
- 先检查
p是否已是 fulfilled/rejected;若是,直接取值,不入队微任务; - 若
p是 pending 状态,则将「当前 async 函数剩余逻辑」包装成一个微任务(即then回调),并注册到微任务队列; - 此时不会提前处理后续的 await 表达式,控制权已让出,JS 引擎继续执行同步代码或处理其他微任务;
- 只有当前 await 的 Promise settled、微任务执行完毕、async 函数恢复后,才会解析并执行下一行(比如下一个
await p2)。
连续 await 的微任务入队是“延迟且分批”的
看这个例子:
const p1 = new Promise(r => setTimeout(r, 0, 'p1'));const p2 = new Promise(r => setTimeout(r, 0, 'p2'));const p3 = new Promise(r => setTimeout(r, 0, 'p3'));async function f() { console.log('start'); const a = await p1; console.log('after p1:', a); const b = await p2; console.log('after p2:', b); const c = await p3; console.log('after p3:', c);}
执行过程关键点:
- 同步输出
start; - 遇到
await p1→ p1 pending → 注册第一个微任务(恢复函数 + 取值逻辑),然后暂停; - 此时 p2、p3 还没被访问,更不会注册任何微任务;
- 等 p1 settle(setTimeout 触发 resolve),第一个微任务执行 → 输出
after p1: p1→ 继续执行下一行; - 此时才计算
await p2→ p2 pending → 注册第二个微任务; - 同理,p3 的微任务只在 p2 settle 后才注册。
对比:直接链式调用 then 与 await 的入队差异
如果写成:
p1.then(() => p2).then(() => p3);
那么三个 then 回调会在 p1 settle 后**一次性全部入队**(因为链式调用是同步解析的),形成连续三个微任务;而连续 await 是「一个 settle → 一个入队 → 一个执行 → 再下一个 await → 再下一个入队」,节奏更松散,中间可能插入其他微任务(如其他 Promise.resolve().then)。
注意:await 表达式本身的求值是同步的
也就是说,await someExpression 中的 someExpression 总是同步求值。例如:
await foo(); await bar();
- 先同步调用
foo(),得到返回值(可能是 pending Promise); - 再同步调用
bar()—— 但这是在foo()返回的 Promise settle 之后才发生的; - 所以
bar()不会在foo()还没返回时就调用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











