理解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();
通过打印的结果可以验证观点:
- 在a b分别赋值后,a b两个任务已经开启并执行;
- 当进行到await时,后续代码才会被阻塞,等待任务完成后继续执行后续代码。