You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript中await的作用、执行时机及与微任务队列的关联

理解JavaScript中await的作用与微任务队列的关系

我是JavaScript新手,想要理解await的具体作用及其与微任务队列的关系。以下为用于说明问题的代码示例:

async function afunc() {
  console.log("a1");
  const b = bfunc();
  console.log("a2");
  b.then((value) => {
    console.log(value);
  });
  return "a value";
}

async function bfunc() {
  console.log("b1");
  await console.log("waiting");
  console.log("b2");
  return "b value";
}

const a = afunc();

a.then((value) => {
  console.log(value);
});

console.log("script end");

执行结果为:

a1
b1
waiting
a2
script end
b2
a value
b value

MDN中提到:

await表达式会暂停async函数的执行,直到Promise状态敲定(已兑现或已拒绝),然后在兑现后恢复函数执行。

我有以下疑问:

  • 这个“恢复执行”具体发生在什么时候?
  • 它与微任务队列的执行顺序有什么关联?
  • 我原本认为b.then()会比a.then()更早进入微任务队列,所以b value应该出现在a value之前,但实际输出与预期不符,对此感到困惑。

补充说明:如果移除bfunc中的await,执行结果变为:

a1
b1
waiting
b2
a2
script end
b value
a value

解答

1. “恢复执行”的时机

当await后跟一个非Promise值(比如这里的console.log("waiting"),它返回undefined),JS会把这个值包装成一个已兑现的Promise。await暂停当前async函数后,会把函数后续的代码(也就是console.log("b2"); return "b value";)打包成一个微任务,添加到微任务队列里。

这个微任务会在当前同步执行栈清空后,下一次宏任务执行前被取出执行——也就是等所有同步代码跑完,才会轮到这个微任务恢复bfunc的执行。

2. await与微任务队列的关联

await本质就是在操控微任务队列:

  • 遇到await时,当前async函数暂停,后续代码被封装成微任务入队。
  • 微任务队列遵循先进先出规则,但必须等当前同步栈的所有代码执行完毕后,才会一次性清空所有已存在的微任务(如果微任务执行中又产生新的微任务,也会被加入队列,继续执行直到队列空)。

3. 为什么a value在b value前面?

我们一步步拆解原代码的执行流程:

  1. 同步执行const a = afunc();,进入afunc:
    • 打印a1,然后调用bfunc()。
  2. 进入bfunc:
    • 打印b1,执行await console.log("waiting")——打印waiting,然后把bfunc后续的console.log("b2"); return "b value";包装成微任务A,加入微任务队列。此时bfunc暂停,返回一个pending状态的Promise给变量b。
  3. 回到afunc:
    • 打印a2,然后给b这个pending的Promise绑定then回调(这个回调要等b的Promise兑现后才会入队),接着afunc返回"a value",此时afunc的Promise状态变为已兑现,它的then回调(打印a value)被包装成微任务B,加入微任务队列。
  4. 同步执行console.log("script end");,此时同步栈清空。
  5. 开始处理微任务队列:
    • 第一个微任务是A:执行bfunc的剩余代码,打印b2,然后把b的Promise状态改为已兑现。这时候,之前绑定的b.then()回调(打印b value)被包装成微任务C,加入队列。
    • 接着执行微任务B:打印a value。
    • 最后执行微任务C:打印b value。

所以最终顺序是b2→a value→b value,和你看到的结果一致。

而当你移除bfunc中的await时,bfunc变成了没有暂停的async函数:

  • 调用bfunc时会同步执行完所有代码:打印b1→waiting→b2,直接返回已兑现的Promise"b value"。
  • 回到afunc,b.then()的回调会立即被加入微任务队列(因为b的Promise已经兑现),而afunc的then回调是在afunc返回后才入队。所以微任务队列里顺序是b.then()回调在前,a.then()在后,执行时就先打印b value再打印a value。

内容的提问来源于stack exchange,提问作者wang9hu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 04:12:11