关于 Promise.all 和 async await 这档子事儿

6,686 阅读4分钟

本文章主要是对比两者之间使用Promise返回的异步函数的区别。

🌰 计算一下执行时间
例子1:所有异步函数均为成功

function promise1(){
    return new Promise(resolve=>{
        setTimeout(()=>{
            resolve()
            console.log("promise1");
        },1000)
    })
}
function promise2(){
    return new Promise(resolve=>{
        setTimeout(()=>{
            resolve();
            console.log("promise2");
        },2000)
    })
}
function promise3(){
    return new Promise(resolve=>{
        setTimeout(()=>{
            resolve();
            console.log("promise3");
        },3000)
    })
}

例子2: 修改第一个promise1函数为失败。

function promise1(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            reject("error")
            console.log("promise1");
        },1000)
    })
}

使用Promise.all

如果我们使用 Promise.all 来执行 例子1 所有的异步函数,并计算时间

console.time("test");
Promise.all([promise1(),promise2(),promise3()]).then(()=>{
    console.log("promise.all执行完毕");
    console.timeEnd("test");
}).catch(()=>{
    console.log("promise.all执行失败");
    console.timeEnd("test");
})

我们会得到如下的执行时间:

image.png
omg,我的老天,这速度太快了。

可以看到Promise.all 会按顺序执行并且不会阻塞线程,而是等待所有异步执行完毕,结束整套执行。 并且会以执行的完成最慢的异步promise3函数作为结束。很明显这是一组全部执行并且正常回调的异步Promise函数。所以执行时间耗时 3秒

接下来让我们看看这个 如果我们将第一个promise1函数修改为reject的回调,会如何执行呢? 代码见例子2

我们会得到如下结果:

image.png

Promise.all这个小调皮居然直接执行自己自身的catch失败回调!然后执行了后续的异步函数,这是个感人的故事。。
所以得出结论:Promise.all 如果遇到失败会立刻执行自身的catch回调并且不会中断后续异步函数的执行。

但是值得需要注意的是,Promise.all只会抛出多个异步函数中第一个执行失败的信息 也就是所有异步Promise函数中第一个reject!

使用async await

有如下代码调用顺序执行 例子1

async function asyncTime(){
    console.time("aysncTime");
    await promise1();
    await promise2();
    await promise3();
    console.log("async 执行完毕");
    console.timeEnd("aysncTime");
}    

会得到如下结果:

image.png

这个时候async就向大家展示了 什么叫"姐就是女王,自信放光芒”,不出意外的阻塞了线程,并且同步按顺序执行并返回。
同样是等待所有异步执行完毕,并结束。只不过和Promise.all不同的是会单一执行一个异步函数并等到当前异步函数执行到resolve再继续下一异步函数。执行时长是按照依次执行完毕的时间累计而成 6秒

同样的接下来让我们看看这个 如果我们将第一个promise1函数修改为reject的回调,会如何执行呢?见例子2

image.png

可以看到会直接中断掉不会进行后续的异步函数执行,并且中断线程,不愧是女王就是有脾气!

需要注意的是如果需要代码保护继续执行的话,可以加入try...catch来进行异常捕捉! 如下代码:

async function asyncTime(){
   console.time("aysncTime");
   try{
       await promise1();
       await promise2();
       await promise3();
       console.log("async 执行完毕");
       console.timeEnd("aysncTime");
   }catch (e) {
       console.log("async 执行失败");
       console.timeEnd("aysncTime");
   }
}

可以正确得到代码保护的结果。虽然会中断剩余异步函数的执行,但是保护了整个线程不会中断!

image.png

总结

Promise.all

1.异步执行多个异步函数,虽然按顺序执行,但是由于异步回调时间不固定的情况下并不能保证执行顺序。
2.不会阻塞线程,只会在合适的时机调用整体resolve|reject的回调函数。
3.遇到执行回调中第一个失败。会立刻执行自身的reject的回调函数,并且只会抛出第一个失败reject,后续遇到reject均不执行。
4.不会因为异步函数的失败,而中断后续所有的异步函数执行。
5.由于是异步执行所有异步函数,可以更快的捕获异常问题。

async await

1.同步执行异步代码,按顺序执行,并阻塞线程保证执行顺序。
2.会阻塞线程。
3.遇到执行回调中第一个失败,报错如果不加try...catch会直接中断线程
4.依次执行保证指定顺序调用异步函数。
5.简洁的使用语法糖。

由此以上总结的特性,可以封装成两个执行异步函数的请求集,用于加载显示百分比进度。
学习总结如有错误,欢迎指正!

写在最后

阿江,最近新建了一个前端摸鱼交流群,欢迎同好的小伙伴一起热闹热闹 快戳这里