es6 深入浅出 之Promise的用法以及理解

512 阅读7分钟

. 前沿


小编一直在项目中使用promise,,但是对promise理解的不是很透彻,总是模棱两可的,所以用的不是很得心应手,最近幸得与空,好好总结学习一下,经过研究总结下来,发现自己一下清晰了好多,不错很有帮助,不过这里都是我自己的理解,可能还有一些不足的地方,还要多多学习,以后还会更新不足的或者错误的地方。


. 一,首先说一下Promise的概念

Promise是异步编程的一种解决方案,说白了就是一个构造函数,他自己本身有race,all,reject,resolve这几个方法,原型上有then,catch两个方法。

二,Promise对象的特点:

  • 1, 对象的状态不受外界影响,promise对象代表一个异步操作,它有三种状态,pending(进行中)、fulfilled(已成功)、rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也是(承诺)这个名字的由来。
  • 2, 一旦状态改变就不会在改变,任何时候都可以得到这个结果,promise对象状态改变的过程只能是:从pending变为fulfilled还有从pending变为rejected.也就是说如果状态发生上述变化后,状态就不会在改变了,这个时候我们称之为resolved已定型。
  • 3, 这就是与事件event不同的地方,事件是如果你错过了,再去监听是得不到结果的。

三,Promise的用法:

  • 1, 首先它是一个构造函数,所以每当我们new一个promise实例,就表示一个具体的异步操作,这个构造函数里边有两个参数,分别是:resolve(成功之后的回调函数)reject(失败之后的回调函数)
  • 2,所以说这个异步操作的结果就是失败或者成功,两者都需要回调函数reject/resolve返回,这里要注意的是跟之前的单纯的回调函数不同,不能用return把操作结果返回。要用回调函数,切记。
. 我个人觉得这玩意还是需要举例子比较好理解一点。我在我的项目中写了一个例子,用来理解promise,

接下来我们先new一个Promise对象

//我是在vue项目中
    mounted() {
        let textPromise = new Promise((resolve, reject) => {
            //这个时候我们做一些异步操作
            setTimeout(() => {
                console.log("执行完成我测试的promise");
                resolve('这里的resolve是成功后的回调');
            }, 3000);

        });
    },

执行上面的代码,就会发现控制台直接打出执行完成我测试的promise

这里需要注意的是我只是new了一个对象,并没有调用它,但是我写在里边的异步操作已经执行了,所以说当我们使用Promise时,需要写在一个函数中,在需要的时候再去运行这个函数,举个例子:

        <div  @click="shishi"></div>
methods:{
       shishi() {
          console.log("点击方法被调用");
            this.promiseTest().then((data) => {
                console.log(data);
            })
        },
        promiseTest() {
            let textPromise = new Promise((resolve, reject) => {
                //这个时候我们做一些异步操作
                setTimeout(() => {
                    console.log("执行完成我测试的promise");
                    resolve('这里的resolve是成功后的回调');
                }, 3000);

            });
            return textPromise;
        },
}

看完上面的代码是不是你自己就有了一些理解了

在promiseTest方法里边 return textPromise;出来这个对象,那么接下来就可以在shishi()方法里边使用Promise对象上的then和catch方法了,这里就表现出来promise的强大之处了。

  • 这个时候你就应该有一些小小的领悟就是原来then里边的函数跟我们平时的一个回调函数是一个意思,它接受resolve传过来的数据,可以在shishi这个点击方法执行完成之后在执行textPromise的回调函数。
  • promise的好处就是当有多层回调时,可以不断的在then方法中继续写promise对象并返回,然后在then方法中进行回调操作。
所以说promise的精髓就是能够简化层层回调,直接在后边链式回调then,比你不断的写callback方法要好的多,也就达到了异步的效果。

所以说promise的正确应用场景是

        <div  @click="shishi"></div>
        methods:{
          shishi() {
            this.promiseTest().then((data) => {
              //这里的data就是promiseTest中textPromise对象中resolve回调方法中返回的值
                console.log(data);
            //然后在这里在把this.promiseTestOne(data);的结果回调给下一个dataOne
        //这里如同回调函数,把第二个的方法传过去才会运行,如果在这里只return,data,那么打印的结果就是
          全是第一个promise里resolve('这里的resolve是成功后的回调');的值。
                return this.promiseTestOne(data);
            }, (reject) => {
                console.log(reject);   //这里就是错误的回调,但是尽量不要写在这里,而是写在catch里
            }).then((dataOne) => {
                //这里的dataOne就是promiseTestOne中textPromise1对象中resolve回调方法中返回的值
                console.log(dataOne);
            }).then((data) =>{
                console.log(data);  //同样这个data还是接受的上个promise中resolve回调的值
                console.log("前边俩方法都调用成功后才会走这个");
            }).catch((data) => {
              //一般情况下你的方法出错不会卡死,而是进入这里。
                console.log(data);   //catch就是用来捕获异常的,所以一般错误都会在这里输出日志
            })
        },
        promiseTest() {
            let textPromise = new Promise((resolve, reject) => {
                //这个时候我们做一些异步操作
                setTimeout(() => {
                    console.log("执行完成我测试的promise");
                    resolve('这里的resolve是成功后的回调');
                  //下边这段代码会执行在reject或者catch中
                    let a = 10;
                    if (a == 10) {
                        reject('这里的reject是失败后的回调');
                    }
                }, 3000);

            });
            return textPromise;

        },
        promiseTestOne(data) {
           //data是接受的第一个promise中的回调值,方便这个promise使用
            console.log("我是第二个方法" + data + "data 是从promiseTest 的resolve 回调传过来的值");
            let textPromise1 = new Promise((resolve, reject) => {
                //这个时候我们做一些异步操作
                setTimeout(() => {
                    console.log("执行完成我测试的promise  测试11");
                    resolve('这里的resolve是成功后的回调' + '测试1');
                }, 3000);

            });
            return textPromise1;
        },
}

以上写法就达到了你想在某个接口完全完成之后在调用下一个接口,也就是异步调用,而不是像你之前那样,同步的调用接口。

其实上边的代码跟注释就一同解释了promiserejectresolvethencatch、这几个方法

接下来说一下all方法,all是跟then方法同级的一个方法,该方法提供了并行执行(也就是多个方法可以共存并且同时执行)异步操作的能力,就是说在所有的异步操作执行完成后并且都是成功的情况下才会执行回调。
  • 也就是说all方法不适合我上边举的例子,all方法适合在多个互不相关的方法需要同时执行成功后在执行某方法时使用
    shishi() {
            Promise.all([this.promiseTest(),this.promiseTestOne()]).then((allResult) => {
                  console.log(allResult);
                  console.log("所有的异步操作执行完成后并且都是成功的情况下才会执行回调");
            }).catch((catchResult)=>{
                  console.log(catchResult);
                })
        },
        promiseTest() {
            let textPromise = new Promise((resolve, reject) => {
                //这个时候我们做一些异步操作
                setTimeout(() => {
                    console.log("执行完成我测试的promise")
                    resolve('这里的resolve是成功后的回调');
                }, 3000);

            });
            return textPromise;
        },
        promiseTestOne() {
            let textPromise1 = new Promise((resolve, reject) => {
                //这个时候我们做一些异步操作
                setTimeout(() => {
                    console.log("执行完成我测试的promise  测试11");
                    resolve('这里的resolve是成功后的回调' + '测试1');
                }, 3000);

            });
            return textPromise1;
        },

里边的注释看完是不是一目了然。

最后再说一下不常用的race方法

race其实是和all是相反的,就是谁先执行完,就先走谁的回调,举个例子,一目了然

注意我把异步的时间改一下

    shishi() {
            Promise.race([this.promiseTest(),this.promiseTestOne()]).then((allResult) => {
                  console.log(allResult);
                  console.log("谁先执行完,就先走谁的回调");
            }).catch((catchResult)=>{
                  console.log(catchResult);
                })
        },
        promiseTest() {
            let textPromise = new Promise((resolve, reject) => {
                //这个时候我们做一些异步操作
                setTimeout(() => {
                    console.log("执行完成我测试的promise")
                    resolve('这里的resolve是成功后的回调');
                }, 2000);

            });
            return textPromise;
        },
        promiseTestOne() {
            let textPromise1 = new Promise((resolve, reject) => {
                //这个时候我们做一些异步操作
                setTimeout(() => {
                    console.log("执行完成我测试的promise  测试11");
                    resolve('这里的resolve是成功后的回调' + '测试1');
                }, 5000);

            });
            return textPromise1;
        },

上面的代码执行结果就是2秒的先执行完毕就已经进入到then里面的了,而于此同时,promiseTestOne也就是5秒的并没有停止,还在运行,于是在过三秒后,输出了各自的回调值。

结束语

最后再说一下,race方法的用法,小编很少用到,所以等慢慢接触到在更新,目前常用的5种。