理解await的串行与并行

1,680 阅读2分钟

理解await的串行与并行

await 表达式会暂停当前 async function 的执行,等待 Promise 处理完成。若 Promise 正常处理(fulfilled),其回调的resolve函数参数作为 await 表达式的值,继续执行 async function。

若 Promise 处理异常(rejected),await 表达式会把 Promise 的异常原因抛出。

另外,如果 await 操作符后的表达式的值不是一个 Promise,则返回该值本身。

这是mdn上关于await的简介,在日常的业务应用中,如果我们要顺序执行 a b 两个异步任务,我们的代码一般如下:

// 串行
function resolveAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

async function f1() {
  console.log(new Date());
  var a = await resolveAfter2Seconds(10);
  var b = await resolveAfter2Seconds(10);
  console.log(new Date());
}
f1();

也正如我们所期望的,这段代码执行完毕需要大于4s的时间,但是如果我们的 a b 任务并无依赖关系,那么并行执行 a b 两个任务就可以节约一半的时间,改造后代码如下:

// 并行
function resolveAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

async function f1() {
  console.log(new Date());
  var a = resolveAfter2Seconds(10);
  var b = resolveAfter2Seconds(10);
  console.log(a);
  console.log(b);
  await a;
  await b;
  console.log(new Date());
}
f1();

这段代码执行时间约为2s,节省了一半的时间,但是为什么这种写法 a b 任务就会并行呢?

查阅一些相关文档后发现原因是在赋值的过程,a b 两个任务已经开始执行,此时两个异步任务时并行的,我们也可以通过控制台来打印结果来验证一下。

async function f1() {
  console.log(new Date());
  var a = resolveAfter2Seconds(10);
  var b = resolveAfter2Seconds(10);
  console.log(a);
  console.log(b);
  // a b 打印结果均为Promise 并且其状态为 pending
  // Promise {<pending>}
  //   __proto__: Promise
  //   [[PromiseState]]: "pending"
  //   [[PromiseResult]]: undefined

  await a;
  await b;
  console.log(new Date());
}
f1();

通过打印的结果可以验证观点:

  1. 在a b分别赋值后,a b两个任务已经开启并执行;
  2. 当进行到await时,后续代码才会被阻塞,等待任务完成后继续执行后续代码。