Promise--异步编程的解决方案

1. 概述

Promise 是ES6新增的对于异步编程的一种解决方案,比普通的回调函数解决异步问题功能更强大

补充知识点:回调函数

下例中的callback函数就称为a函数的回调函数

        function a(fn) {
            fn();  //a回调一下fn
        }
        function callback() {
            console.log('1111'); 
        }
        a(callback);  //1111

2. 创建promise 使用new关键字

        const pro1 = new Promise(function (res,rej) {
            setTimeout(function(){
                console.log('pro1包含的异步操作');
            },1000)
        });

3. promise对象的三个状态

pending:进行中

fulfilled:已完成--成功

rejected:已失败--失败

特性:promise的状态只能从pending--->fullfiled 或者 从pending--->rejected,promise对象的状态一旦改变,就不会发生第二次改变

const pro1 = new Promise(function (res,rej) {
    setTimeout(function(){
         console.log('pro1包含的异步操作');
       //res('pro1成功后的promise结果')  //将异步结果状态从pending(进行中)转为fulfilled(已完成/成功的)

         rej('pro1失败后的promise结果')  //将异步结果状态从pending(进行中)转为rejected(已失败/失败的)
       //这两个实参是函数,只能运行一个,不可能说既成功又失败
     },1000)
});

4. 异步的解决方案解释

我们可以在new Promise的回调函数中定义任意的异步操作,至于状态最终结果是成功fullfiled 还是失败rejecte,都是由我们自己决定的。

那外面如何捕获promise的结果呢?需要用到promise原型链中的then方法

 5. 特性

promise对象一旦产生,就会立马执行,有时候我们需要的是在调用它的时候才执行,所以可以采用封装函数来解决这个问题。

        function getPromise() {
            return new Promise ((res,rej)=>{
                setTimeout(function(){
                    res('返回成功结果')
                },1000)
            })  
        }
        const pro1 = getPromise();  
        console.log(pro1);  //'返回成功结果'
        //下次需要使用该promise对象时,又在声明调用一次
        const pro2 = getPromise();

6. 方法

6.1 实例对象的方法

1. .then( )方法

返回结果为一个新的promise对象

pro2是由Promise创建出来的,所以pro2.__proto__ == Promise.prototype。Promise.prototype里面有then方法,那么pro2就可以直接用then方法。

new Promise(function (参数1,参数2) 一些异步操作)

这个是声明promise对象的固定搭配,其中参数1和参数2是固定的,是函数。参数1表示异步操作成功的函数,参数2表示异步操作失败的函数。

const pro2 = new Promise(function (res,rej) 
     setTimeout(function(){
        console.log('pro1包含的异步操作');
      //res('异步执行完成的结果')  
//res()调用,得到promise对象产生的结果(字符串'异步执行完的结果') .then方法就会立马执行里面的第一个函数,并且将res参数传给第一个函数

        rej('异步执行失败的结果')  
//将res参数:结果(字符串'异步执行失败的结果')传给.then方法的第二个函数
            },1000)
        })
pro2.then(function(rig){
     console.log(rig);   //成功,就打印rig实参的内容
     },function (err) {
     console.log(err);   //失败,就打印err实参的内容
});

注意:在手动调用res/rej函数可以把promise状态置为成功/失败,需要满足代码逻辑不能出错,下面展示三种代码逻辑出错的情况

情况一:不符合逻辑的代码出现在res/rej函数之前,程序卡住,无法设置promise的结果

        const pro3 = new Promise(function (res,rej) {
            setTimeout(function(){
                console.log('pro1包含的异步操作');
                console.log(x);
                res('异步执行完成的结果')  
            },1000)
        })
//结果打印'pro1包含的异步操作',然后报错(is not defined)
//后面的res会卡住,不能设置promise的结果

情况二:

        const pro3 = new Promise(function (res,rej) {
            setTimeout(function(){
                console.log('pro1包含的异步操作');
                var x = '异步执行完成的结果';
                res(x);
            },1000)
        })
//不能打印'异步执行完成的结果',卡住,无法将promise结果置为成功

情况三:先设置promise的结果,再出现不符合逻辑的代码,并不影响promise的结果。promise的结果一旦发生改变,就不会再更改。

        const pro3 = new Promise(function (res,rej) {
            setTimeout(function(){
                console.log('pro1包含的异步操作');

                res('异步执行完成的结果');
                console.log(x);
            },1000)
        }) 
        console.log(pro3);   后面不会卡住 已经成功了
//[[Prototype]]: Promise 
//[[PromiseState]]: "fulfilled" 
//[[PromiseResult]]: "异步执行完成的结果"

 2. catch方法以及链式调用

.then( ).catch( )

.catch( )是为了替代.then中的第二个回调函数,用来捕获promise对象的错误,它可以捕获它之前的错误。下例中pro3调用了r(),就触发了pro3.then(),将'异步成功'作为参数传给.then()并打印,接下来.then()里面代码出现了逻辑错误(console.log(x)),因此就触发了.catch(),将'x is not defined'作为参数传给.catch()并打印。

const pro3 = new Promise((r,j)=>{
            r('异步成功');
            // j('异步失败')
        })
        pro3.then(res=>{
            console.log(res);  //异步成功
            console.log(x);
        }).catch(err=>{
            console.log(err);  //ReferenceError: x is not defined
        })

总结:new Promise( )中的操作代码逻辑没问题,直接走下一个.then里面去,并且会把return的结果作为下一个.then的参数;如果出现问题,就是走到.catch,将return的结果作为.catch的参数。

         const pro4 = new Promise((r,j)=>{
            r('异步成功');  //传给res1作为参数
            //j('异步失败')
        })
        pro4.then(res1=>{
            console.log(res1);  //异步成功
            return 'res1成功'  //传给res2作为参数
        }).then(res2=>{
            console.log(res2);  //res1成功
        }).catch(err=>{
            console.log(err);  //没有错误可以捕捉,因此不打印
        })

链式调用的练习题

const pro3 = new Promise((resolve, reject) => {
            resolve('one');  //promise结果为成功,将one传入.then()的实参中
        });
        pro3
            .then((val) => {
                console.log(val); // 'one'
                return x;  //出现错误,接下来走.catch(),将'x is not defined'传给.catch
            })
            .then((val) => {
                console.log(val);
            })
            .catch((err) => {
                console.log(err); // 'x is not defined'
                console.log(typeof err); // object
                return err;  //返回'x is not defined'以供接一下来的.then使用
            })
            .then((val) => {
                console.log(val); // 'x is not defined'
            })
            .catch((err) => {
                console.log(err);
            })

3. .finally ()方法

Promise.prototype.finally。不管promise对象的状态是成功还是失败,都一定会触发finally里面的方法。它存在的意义是,无论成功还是失败,都要进行的操作(比如:无论请求失败还是成功,都要让网页的loading停下来)

6.2 Promise本身的方法(只能通过Promise去调用)

1. Promise.all

将几个promise对象放在一个数组里面,返回一个新的promise对象,同样也可以使用前面的方法。只有当数组中所有的promise对象都成功时,它才会走到.then里面表示成功;一旦有一个promise对象失败/出错,那结果就走到.catch方法。

2. Promise.resolve(参数)

将现有的对象转为promise对象:

        a. 如果现有对象本身就是promise对象,则该方法直接返回原promise对象(引用地址也一样)

        b.参数是一个thenable对象,立马将该对象转为promise对象,并且立马执行它自己的then方法(不是promise实例对象的then方法,是thenable对象内的一个方法名而已,但不能更改这个方法名),将这个promise对象变为成功/失败状态

解释thenable对象:这个对象里面有如下所示的then方法的对象

        const obj = {
            then:function(res,rej){
                res('成功了');
                // rej('失败了');
            }
        }
        const pro6 = Promise.resolve(obj);
        pro6.then(r=>{
            console.log(r);  //成功了,说明obj转化为promise对象时就是pro6
        }).catch(e=>{
            console.log(e);
        })

        c. 参数不是thenable对象 或 不是对象,则返回一个已经resolve(成功)状态的promise对象,并且该promise对象的结果为传入的参数

        d.参数为空,则返回一个已经resolve(成功)状态的promise对象,结果为undefined

2. Promise.reject()

返回一个已经rejected(失败)状态的promise对象。传入的参数直接被当成是失败的结果

,用.catch来捕捉这个错误

你可能感兴趣的:(javascript,vue.js,node.js)