async/await 题目分析

3 阅读1分钟

这道题其实是 async / await + Promise + 事件循环 的经典执行顺序题。
核心是理解:

  1. async 函数 会立即执行同步代码
  2. await 相当于 Promise.then(微任务)
  3. async 函数 默认返回 Promise
  4. await 后面的代码 会被放入微任务队列

我们一步一步拆。


一、代码结构

代码大致是:

console.log(1)

async function async1() {
  await async2()
  console.log(2)
  await async3()
  console.log(3)
}

async function async2() {
  console.log(4)
}

async function async3() {
  console.log(5)
}

async1()
console.log(6)

二、执行流程

1 先执行同步代码

第一行:

console.log(1)

输出

1

2 执行 async1()

async1()

进入 async1

执行

await async2()

先执行 async2()


3 执行 async2()

async function async2() {
  console.log(4)
}

这是同步代码:

输出

4

async2() 返回

Promise.resolve(undefined)

所以

await async2()

等价于

Promise.resolve().then(...)

于是:

console.log(2)

被放入 微任务队列


4 回到主线程继续执行

继续往下执行同步代码:

console.log(6)

输出

6

三、开始执行微任务

此时微任务队列有:

console.log(2)

执行:

2

5 执行 await async3()

await async3()

先执行 async3()


async3()

console.log(5)

输出

5

返回

Promise.resolve()

于是

console.log(3)

进入 新的微任务


四、执行最后微任务

输出

3

五、最终输出顺序

1
4
6
2
5
3

六、一张流程图理解

主线程
│
├─ console.log(1)
│
├─ async1()
│   │
│   ├─ async2()
│   │   └─ console.log(4)
│   │
│   └─ await → 微任务(console.log(2))
│
├─ console.log(6)
│
└─ 执行微任务
    │
    ├─ console.log(2)
    │
    ├─ async3()
    │   └─ console.log(5)
    │
    └─ 微任务(console.log(3))

七、面试官最想听的总结

一句话版本:

await 会暂停 async 函数,把后面的代码放进微任务队列。

所以执行顺序遵循:

同步代码
→ 微任务 (Promise.then / await)
→ 宏任务 (setTimeout)

八、一个更本质的理解(高级面试)

很多人不知道:

await asyncFn()

真正等价于

Promise.resolve(asyncFn()).then(() => {
   // await 后面的代码
})

所以:

await = Promise.then(微任务)