0%

javascript-async-await

await后面的代码是同步执行吗?

asyncpromise并无本质区别,async只是看起来更加同步,本质还是异步执行。来看一段代码。

1
2
3
4
5
6
7
8
async function foo() {
console.log(1);
await Promise.resolve();
console.log(2);
}

foo();
console.log(3);

这段代码的输出结果是:1 3 2。而不是1 2 3。await会等待右侧的Promise执行完毕,并将后续代码 - console.log(2)加入微任务队列。所以上述代码的执行过程是:

  1. 执行console.log(1),输出1
  2. 执行await Promise.resolve(),将后续代码console.log(2)加入微任务队列
  3. 执行console.log(3),输出3
  4. 执行微任务队列中的代码,输出2

我们可以将foo改写一下,它实际上等价于下面的代码。

1
2
3
4
function foo() {
console.log(1);
Promise.resolve().then(() => console.log(2));
}

由此,我们可以得出如下结论:

  • await右侧的Promise同步执行。
  • await后续的代码会在Promise resolve后背加入微任务队列等待后续执行。

再看一个例子:

1
2
3
4
5
6
7
8
9
10
11
async function test() {
console.log("A");
await new Promise(resolve => {
console.log("B");
setTimeout(resolve, 0); // 宏任务触发 resolve
});
console.log("C");
}

test();
console.log("D");

这段代码的输出结果是:A B D C。执行过程如下:

  1. 首先执行test函数中的console.log("A"),输出A
  2. 然后执行await右侧的Promise,由于console.log("B")是同步代码,所以输出B
  3. 执行setTimeout(resolve, 0),将resolve加入宏任务队列
  4. 执行console.log("D"),输出D
  5. 注意此时微任务队列为空,所以执行宏任务队列中的resolve,此时await右侧的Promise执行完毕,将后续代码console.log("C")加入微任务队列
  6. 执行微任务队列中的代码,输出C

再看一个例子,你知道以下代码输出什么结果吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
async function async1() {
console.log(1);
await Promise.resolve().then(() => console.log(4));
console.log(2);
}

const async3 = async () => {
Promise.resolve().then(() => {
console.log(6);
});
};

async1();
console.log(7);
async3();

答案是:1 7 4 6 2。来分析一下执行过程:

  • 执行async1(),输出1
  • 执行await Promise.resolve().then(() => console.log(4)),此时将console.log(4)加入微任务队列。
  • 执行console.log(7),输出7
  • 执行async3(),将console.log(6)加入微任务队列
  • 执行微任务队列中的代码console.log(4),输出4,此时async1中的await右侧的Promise执行完毕,将后续代码console.log(2)加入微任务队列
  • 执行微任务队列中的代码console.log(6),输出6
  • 执行微任务队列中的代码console.log(2),输出2

总结一下:

  • 遇到await时,await会暂停当前async函数的执行,并等待右侧的Promise执行完毕,然后async函数后续代码加入微任务队列。
  • await只是暂停当前async函数的执行,并不会阻塞主线程的执行。当前async函数外的代码会继续执行。
  • 从影响范围来说,await只影响当前async函数,不影响其他函数。

await与Promise链

In JavaScript, await can works with promise chain, it will get the resolved value of the last promise in the chain. For example:

1
2
3
4
5
6
7
8
9
10
11
getData = () =>
Promise.resolve(1)
.then(() => 2)
.then(() => 3);

async function test() {
const res = await getData(); // output: 3
console.log(res);
}

test();

In above code, getData() returns a promise chain, the resolved value of the last promise in the chain is 3, so the output of the code is 3.

You can even append more promise chain when calling getData()

1
2
3
4
5
6
async function test() {
const res = await getData()
.then(() => 4)
.then(() => 5);
console.log(res); // output: 5
}