# Promise async/await 理解和应用

lxf2023-04-09 18:12:02

Promise async/await 理解和应用

Promise的作用与用法

Promise是异步编程的一种解决方法

  • 是一种容器,保存某个未来才会结束的事件(通常是一个异步操作)的结果
  • 语法Promise是一个对象,可以获取异步操作的消息
  • Promise提供统一的API,各种异步操作都可以用同样的方法进行处理

Promise对象的特点

对象的状态不受外界影响。

三种状态:

  • pending(进行中)
  • fulfilled(已成功)
  • rejected(已失败)

一旦状态改变就不会在改变,任何时候都可以得到这个结果。

状态改变只有两个可能:

  1. pending变为fulfilled

  2. pending变为rejected

只要出现这两个情况,状态就凝固了,不会再改变,这个时候就成为resolved(已定型)。

基本用法

ES6规定,Promise对象是一个构造函数,用来生成Promise实例

Promise.resolve()方法

返回一个具有给定值的Promise对象。

Promise.reject()方法

返回一个具有给定值的Promise对象。

Promise实例的方法

  1. then()
  2. catch()
  3. finally()
then()

then()执行的回调函数会放在微任务队列中,并且注册到Promise里面。then()的返回值是Promise,如果没有返回值,相当于返回undefined。返回的Promise对象,其状态和你当前调用的resolvereject有关。

微任务和宏任务:当执行栈清空,先执行微任务队列,待微任务队列清空,在执行宏任务队列,执行完之后,再去查看微任务队列。

catch()

catch()方法是.then(null, rejection).then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

Promise对象的错误会有冒泡的性质,会一直向后面传递,一直大奥被捕获才停止。Promise对象抛出的错误不会传递到外层代码

在链式调用里面catch()也会返回一个Promise,如果执行完成,没有报错状态就是fulfilled

finally()

之前的作业里面也遇到过finally(),这个方法用于指定,不管Promise对象的最后状态是怎么样,都会执行的操作。

缺点

  • 无法取消,建立马上执行
  • 不设置回调参数,Promise内部抛出错误,不会反应到外部
  • 处于pending状态,无法得知目前进度是刚开始还是即将完成

异步编程与Promise的关系

前端Js的代码是在浏览器的Js引擎中执行的,并且Js的引擎是单线程,也就是不能同时执行多个,只能一个执行完,再去执行下一个。异步的理解就是把等待请求响应的这段时间,交给Js的主线程,让它去做别的事情,等待响应回来后再去执行这个任务的后续操作。

举个简单的例子,王者荣耀马超这个英雄很需要经济,这样就可以在很多方面打出巨大优势。可以让马超在我方中路去支援的时候,吃中路线,等中路回来后,就可以再一起去上路搞事,这个是可以提高对局胜率的一种做法。

Js是怎么实现异步操作:

  1. 回调函数
  2. Promise
  3. async/await

回调函数的理解

顾名思义,就是回头来调用函数。

把请求的动作和响应的动作分开,然后把响应的动作单独拿出来放在一个函数里面,待执行这个任务的时候,就调用这个函数。

这里可以延伸出一个概念,回调地狱:存在异步任务的代码,不能按照顺序执行,上文已经介绍Promise的一些基本用法,Promise是干什么的?是用来解决回调地狱而产生的,并且进行嵌套,改成链式调用。

就比如我要按照1,2,3的顺序打印,就必须设定定时器才能实现。

# Promise async/await  理解和应用

# Promise async/await  理解和应用

在这段代码,嵌套了三层,这种情况就是回调地狱,很难维护而且代码可读性是真的很差。

Promise是Js中的一个原生对象,也是几乎最佳的异步解决方案,可以替换传统的回调函数。

上述代码优化方案如下:

function fn(str){
            var p=new Promise(function(resolve,reject){
                //处理异步任务
                var flag=true;
                setTimeout(function(){
                    if(flag){
                        resolve(str)
                    }
                    else{
                        reject('ERROR')
                    }
                })
            })
            return p;
        }

        fn('1')
        .then((data)=>{
            console.log(data);
            return fn('2');
        })
        .then((data)=>{
            console.log(data);
            return fn('3')
        })
        .then((data)=>{
            console.log(data);
        })
        .catch((data)=>{
            console.log(data);
        })

# Promise async/await  理解和应用

但是Promise其实还存在着另外一个问题,代码冗余很大,一眼望去都是then()...

一样是不利于维护的。

async/Await

async关键字

其作用是把关键字放在声明函数前面,告示该函数为一个异步任务,并且不会阻止后面的函数正常执行。

 async function fn(){
            return '1';
        }
        console.log(fn());

# Promise async/await  理解和应用

打印结果可以看得出来,他将返回的数据进行了一个封装操作,变成了一个Promise对象。和Promise一样,在执行异步任务的时候也按照成功和失败来返回不同的数据,处于成功用then,失败则使用catch接收。

 async function fn() {
            var flag = true;
            if (flag) {
                return '2';
            }
            else{
                throw '任务处理失败'
            }
        }
        fn()
        .then(data=>{
            console.log(data);
        })
        .catch(data=>{
            console.log(data);
        })

        console.log('FAST RUN');

会先执行FAST RUN。

# Promise async/await  理解和应用

如果把flag的值改成false,则会调用catch打印任务处理失败。

await关键字

该关键字只能在async定义的函数里面使用,可以直接跟Promise对象。

 function fn(str) {
            var p = new Promise(function (resolve, reject) {
                var flag = true;
                setTimeout(function () {
                    if (flag) {
                        resolve(str)
                    } else {
                        reject('任务处理失败')
                    }
                })
            })
            return p;
        }

        //封装一个执行上述异步任务的async函数
        async function test(){
            var res1=await fn('先跑到中路');  //await直接拿到fn()返回的promise的数据,并且赋值给res
            var res2=await fn('吃中线');
            var res3=await fn('回上路继续吃线');
            console.log(res1,res2,res3);
        }

# Promise async/await  理解和应用

await关键字如其名,等待。当async函数执行到await的时候,就开始等待在此处,不再继续往下执行,等await拿到了Promise中的resolve的数据,才会继续往下执行任务,这样保证了代码的顺序执行,也可以看着这个异步操作,更像是一个同步任务一样。

总结

  • promiseasync/await是专门用于处理异步操作的。
  • async/await使用上更为简洁,将异步代码以同步的形式进行编写,是处理异步编程的最终也是最佳方案。