• 你了解Promise么


    ECMAScript 6.0(es6)已经出来三年多了,相对es5,es6有很多新特性值得我们去探究,其中Promise对象可以说真的是很有趣呢!笑哭.jpg

    Promise是什么?他可是对象啊。你能亲手new一个promise,然后让他为你做他能做到的事情,就算做不到,你还能给他加技能,想想就很开心。

    js是一门神奇的语言,他成功做到了把函数作为参数。

    下面的代码很容易理解的:

    var wait=function (time,callback) {
        setTimeout(function () {
            callback();
        },time)
    };
    wait(300,function () {
      console.log('等300ms我该做点啥呢?');
      //todo
    })

     这里的wait是个函数,它接收两个参数,其中的callback就是一个函数。

    这时候你是不是想说,回调用着还蛮带劲的,别别别,当你遇到多重回调你会疯掉的,前方高能,请做好一级战斗准备:

     var fun=function (callback1,callback2,callback3) {
            var data=1;
            setTimeout(function () {
                console.log('first:'+data);
                callback1(callback2,callback3,data)
            },1000)
        };
        var callback1=function (callback2,callback3,data) {
            setTimeout(function () {
                console.log('second:'+data);
                callback2(callback3,data)
            },1000)
        };
        var callback2=function (callback3,data) {
            setTimeout(function () {
                console.log('third:'+data);
                callback3(data)
            },1000)
        };
        var callback3=function (data) {
            setTimeout(function () {
                console.log('firth:'+data);
            },1000)
        };
        fun(callback1,callback2,callback3);

    怎么样?惊不惊喜意不意外开不开心?就为了传个数据,就写了四个函数,这特么还能不能愉快的写代码了?

    别急,这时候可以有请我们的Promise闪亮登场了。

    且看下面一段代码:

    var fun = function () {
            return new Promise(function (resolve, reject) {
                setTimeout(function () {
                    console.log('first:1');
                    resolve('1')
                }, 1000)
            })
        };
        fun()
            .then(function (data) {
                return new Promise(function (resolve, reject) {
                    setTimeout(function () {
                        console.log('second'+data);
                        resolve(data)
                    }, 1000)
                })
            })
            .then(function (data) {
                return new Promise(function (resolve, reject) {
                    setTimeout(function () {
                        console.log('third'+data);
                        resolve(data)
                    }, 1000)
                })
            })
            .then(function (data) {
                return new Promise(function (resolve, reject) {
                    setTimeout(function () {
                        console.log('firth'+data);
                        resolve(data)
                    }, 1000)
                })
            })

     怎么样,这一波链式操作是不是看起来舒服多了?舒服是舒服,就是有点儿不理解。那么我们就来一点点分析。

    上面的代码中:fun可是一个正经的函数,它的返回值是一个promise对象。我们看到,promise对象还有一个then属性,这个then是做什么的呢,我们后面会介绍。

    promise就是一个代表了异步操作最终完成或者失败的对象,既然promise是个对象,那他自然有自己的构造函数。promise的构造函数接受一个函数参数,这个函数有两个参数,都是由js引擎提供,不需要自己去实现的。

    第一个参数resolve(当然你命名成阿猫阿狗都行的)表示将Promise的状态置为fullfiled,reject是将Promise的状态置为rejected。这么说可能有些晦涩难懂,其实吧,他们都是函数,这个函数什么时候执行呢?这取决于你。不过我们约定俗成的做法是,在异步操作执行成功的时候,调用resolve,在异步操作执行失败的时候调用reject。resolve和reject都要结合promise的then属性来使用,then是一个函数,他的两个参数分别对应promise的resolve和reject。

    这段代码的执行结果如下图(每隔一秒输出一行):

    上面只验证了resolve,我们再来验证下reject:

    可能你会问,这并不是异步操作啊?对的,这确实不是异步操作,这只是为了验证promise构造函数里面的resolve和reject与then属性的回调函数对应关系,你甚至可以这么写:

    到这里,想必你已经对Promise已经有了大致的了解,没错,promise就是一个普通的拥有着众多属性的对象,那么我们继续看看promise原型上的方法吧(哈?你问什么是原型,那么出门右拐,说不定能找到原型的介绍~)。

    1、then

      为promise实例提供状态改变时的回调函数。(前面已经介绍了,这里就不继续废话了)

    2、catch

      我们都知道以下写法:

     try{
            //somecode
        }catch(error){
            
        }

       普通的catch的作用是用来捕获try里面的代码块执行过程中的异常或错误,如果“somecode”里面有错误,不捕获的话就会影响后续的代码执行,这样就可能对整体代码造成创伤。

      和普通catch一样,Promise原型上的catch方法能捕获到resolve里面的异常,举个栗子:

    new Promise(function (resolve, reject) {
                setTimeout(function () {
                    console.log('first:1');
                    resolve('1')
                }, 1000)
            }).then(function(data){
                 console.log(someVal);
            }) .catch(function(reason){
                console.log('出错了:');
                console.log(reason);
            });    

      来看下控制台执行结果:

      

      可以看到,Promise的catch与普通的catch方法有着相似的功能。

      再来看一个栗子:

    new Promise(function (resolve, reject) {
                setTimeout(function () {
                    reject('1')
                }, 1000)
            }).then(function(data){
                 console.log(someVal);
            }) .catch(function(data){
                console.log(data);
            });   

      执行结果如下:

      

      所以说,catch的回调可以当成reject即then的第二个函数来使用。

    3、finally

      finally的字面意思是最终的,在promise对象上表示这个对象最终执行的方法,就是说,不管是resolve还是reject,最终都会进finally方法。

      来看代码:

      

    new Promise(function (resolve, reject) {
        setTimeout(()=>{resolve(1);},1000)
        setTimeout(()=>{reject(2);},2000)
    })
        .then(result => {console.log(result)})
        .catch(error => {console.log(error)})
        .finally(() => {console.log('finally')});

      执行结果如下:

      

      在这个栗子中,Promise中的状态为fulfilled,但在执行了resolve方法后,还是输出了‘finally’。

      其实:finally()方法返回一个promise对象,在执行then()和catch()后都会执行finally指定的回调函数,避免同样的代码在then和catch中都写一次,什么意思呢?且看:

    new Promise(function (resolve, reject) {
        setTimeout(()=>{resolve(1);},1000)
        setTimeout(()=>{reject(2);},2000)
    })
        .then(result => {console.log('我是异步操作之后必须要执行的代码')})
        .catch(error => {console.log('我是异步操作之后必须要执行的代码')})

    输出如下:

      

      其实,针对上述代码,finally就能搞定,你只需要这样写就行:

    new Promise(function (resolve, reject) {
        setTimeout(()=>{resolve(1);},1000)
        setTimeout(()=>{reject(2);},2000)
    })
        .finally(() => {console.log('我是异步操作之后必须要执行的代码')})

      不信你就执行看看啊。

    讲完了Promise原型上的方法,接下来我们来讲讲Promise构造函数内的方法。

    1、all

      

    Promise.all([new Promise(function (p1, p2) {
      setTimeout(() => {
        console.log(1);
        p1(1)
      }, 1000)
    }),
      new Promise(function (p1, p2) {
        setTimeout(() => {
          console.log(2);
          p1(2)
        }, 2000)
      }), new Promise(function (p1, p2) {
        setTimeout(() => {
          console.log(3);
          p1(3)
        }, 3000)
      })]).then(function (results) {
      console.log(results);
    })

    先看看执行结果:

    我们来分析一下:all方法接收一个数组作为参数,这个数组的元素全是Promise实例,当这三个Promise的状态都改变时,会进入到all对应的Promise构造函数的then方法,这个then的回调函数参数则是all方法接收的Promise传递的数据封装后的数组。

    也就是说,有了all,你可以并行执行多个异步操作,all会把所有异步操作的结果放进一个数组中传给then。这在很多场景下都适用。比如说某个页面,ABC资源的加载的都是异步的,且之间没有依赖关系,我们需要在ABC资源都加载完成后才执行一些神操作,那么这时候all就可以解决这个问题。

    2、race

      race和all的代码格式差不多,怎么办,我懒得贴代码了,口述吧。

      前面我们说all时等所有的异步操作完成后会进入then的回调,这里的race就不一样了,它表示只要有异步操作执行完了,就会就如then回调,且不影响其他的异步操作的执行。

      哎,还是贴贴一段代码吧。

      

      看到了吧,这里输出了两个1,第二个1时执行最快的那个Promise传个race的then回调了。那么race有什么用了,它作用大着呢,它可以可以给某个异步操作设置超时时间。比如说:

      

    3、resolve

     这时候你是不是懵逼了,怎么构造函数内部还有resolve方法,他不是构造函数的回调的参数么?哈哈,没办法,Promise创始人让它有的,我们没办法阻止的。

      resolve方法返回一个以给定值解析后的Promise对象。

       

      也就是说,resolve会返回一个Promise的实例,这个实例的then方法的第一个回调函数能获取到resolve传过去的数据,进而对数据进行操作。

    4、reject

      与resolve差不多,这里就不细讲了。

    呼,总算写完了~~~~~~~~

      

      

  • 相关阅读:
    java 原子性 可见性 有序性
    java中Array/List/Map/Object与Json互相转换详解(转载)
    观察者模式(转载)
    TCP协议
    “数字签名”与“数字证书”
    两道笔试题
    定时任务处理过程中的问题
    行数据库VS列数据库
    B树和B+树
    ThreadPoolTaskExecutor介绍
  • 原文地址:https://www.cnblogs.com/dasianer/p/9258171.html
Copyright © 2020-2023  润新知