async/await把异步变同步的原理

1. 问题

首先我们来看一段代码,你觉得这段代码的执行顺序是什么呢?

function resolveAfter2Seconds() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('resolved');
    }, 2000);
  });
}

async function asyncCall() {
  console.log('calling');
  const result = await resolveAfter2Seconds();
  console.log(result);
  console.log('A');
  
}

asyncCall();
console.log('B');

这段代码的输出顺序是:

1. "calling" (调用asyncCall函数时打印出来)

2. "B" (在asyncCall函数调用期间打印出来)

3. "resolved" (resolveAfter2Seconds函数中的Promise在2秒后被解决,await关键字等待解决并返回结果)

4. "A" (在await表达式之后打印出来)

2. 原因

那么为什么A是在最后才打印出来呢?这就是因为await会阻碍函数的执行,并一直等待Promise执行结束。

当调用asyncCall函数时,它会立即打印出"calling"。然后,它会在resolveAfter2Seconds函数中等待2秒钟,直到Promise解决为止。在等待期间,控制权返回给调用者,所以在等待期间打印的是"B"。当Promise解决后,结果被赋给result变量并打印出"resolved"。最后,控制权回到asyncCall函数,它继续执行并打印出"A"。

A是在"resolved"之后打印的,原因是在async函数中的await关键字。await关键字会暂停函数的执行,直到Promise解决为止,并返回解决的结果。在这种情况下,await关键字会等待resolveAfter2Seconds函数中的Promise解决,然后将解决的结果赋给result变量。 在这段代码中,当调用asyncCall函数时,它会立即打印出"calling"。然后,它会遇到await关键字,这会导致函数暂停执行并等待Promise解决。在等待期间,控制权返回给调用者(即全局作用域),所以在等待期间打印的是"B"。当Promise在2秒后解决时,await关键字会将解决的结果(即'resolved')赋给result变量。然后,控制权回到asyncCall函数,它继续执行并打印出"A"。 因此,"resolved"是在"A"之前打印的,因为await关键字会等待Promise解决,然后才会继续执行后面的代码。

3. 思考

通过上面的案例我们知道,当使用了await,Promise函数会进入等待期,会造成堵塞,但是会把控制权交给调用者,那我们做个拓展

3.1 把Promise中的定时器设置为0s

function resolveAfter2Seconds() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('resolved');
    }, 0);
  });
}

.......
//其余代码和上方相同

我们发现该种情况下的结果仍然和之前一样,这也代表了即使定时器是0s,Promise仍然会把控制权交给全局,等全局结束同步任务之后,Promise才执行

猜你喜欢

转载自blog.csdn.net/weixin_48975022/article/details/132421946
今日推荐