你了解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差不多,这里就不细讲了。

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

 

 

  

 

 

 

 

  

 

posted @ 2018-07-25 16:33  大仙儿呀  阅读(272)  评论(1编辑  收藏  举报