Promise简要分析

Promise的含义

Promise是异步编程的一种解决方案,比传统的解决方案–回调函数和事件–更合理和更强大。

所谓promise,简单来说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的信息。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。

Promise对象有以下两个特点。

(1)对象的状态不受外部影响。Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Fulfilled(已成功)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字由来,它的意思是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Fulfiled和从Pending变为Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这是就称为Resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过它,再去监听,是得不到结果的。

Promise也有一些缺点。首先无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于Pending状态时,无法得知目前进展到哪个阶段(刚刚开始还是即将完成)。

resolve 和 reject

下面创建一个Promise实例。

 
function helloWorld(flag){ return new Promise(function(resolve, reject){ if(flag){ resolve('成功') }else{ reject('失败') } }) }

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject。它们是两个函数,由Javascript引擎提供,不用自己部署。

  • resolve函数作用:将Promise对象状态变为“成功”;一般在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。
  • reject函数作用:将Promise对象状态变为“失败”;一般在异步操作失败时调用,并将异步操作的错误,作为参数传递出去。

then 和 catch

promise实例生成以后,可以用then方法分别指定Resolved状态和Rejected状态的回调函数。

then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为Resolved时调用,第二个回调函数是Promise对象的状态变为Rejected时调用。第二个参数是可选的。这两个函数都接受Promise对象传出的值作为参数。

catch方法是then(onFulfiled, onRejected)方法当中onRejected函数的一个简单的写法,也就是说可以写成then(fn).catch(fn),相当于then(fn).then(null, fn)。使用catch的写法比一般的写法更清晰明确。

 
helloWorld(true).then(function(){ //success `Resolved`状态 },function(){ //failure `Rejected`状态 }) //then..catch 方式 helloWorld(true).then(function(){ //success `Resolved`状态 }).catch(function(){ //failure `Rejected`状态 })

Promise.all 和 Promise.race

Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例。

Promise.all可以接收一个元素为Promise对象的数组作为参数,当这个数组里面所有的Promise对象都变为resolve时,该方法才会返回。

 
var pro2 = new Promise((res, rej) => { setTimeout(function () { console.log('222'); res('222'); }, 5000); }) var pro3 = new Promise((res, rej) => { setTimeout(function () { console.log('333'); res('333'); }, 1000); }) var pro4 = new Promise((res, rej) => { setTimeout(function () { console.log('444'); res('444'); }, 4000); }) Promise.all([pro2, pro3, pro4]).then(function(result){ console.log(result) }) // 333, 444, 222 // [222, 333, 444]

注意点:[pro2, pro3, pro4]中的promise没有依赖关系,不会按顺序执行。但是返回的值都会按照顺序且返回一个数组。

Promise.race同样接收一个数组,不同的是只要数组中Promise对象中有一个率先改变状态(无论是resolve还是reject),该方法就会返回。

Promise.resolve

有时需要将现有对象转为Promise对象,Promise.resolve方法就起到这个作用。

 
var res = Promise.resolve('foo') // 等价于 var res = new Promise(resolve => resolve('foo'))

Promise.reslove方法的参数分为四种情况:

  • 参数时Promise实例

    那么Promise.resolve将不做任何修改,原封不动地返回这个实例

  • 参数是一个thenable对象(指的是具有then方法的对象)

    Promise.resolve方法会将这个对象转为Promise对象,然后就立即执行thenable对象的then方法。

     
      
    let thenable = { then: function(resolve, reject) { resolve(42); } }; let p1 = Promise.resolve(thenable); p1.then(function(value) { console.log(value); // 42 });
  • 参数不是具有then方法的对象,或根本就不是对象

    返回Promise对象,状态为Resolved

  • 不带有任何参数

    直接返回一个Resolved状态的Promise对象。

Promise.reject

Promise.reject()返回一个新的Promise实例,且该实例状态为rejected

 
var p = Promise.reject('出错了'); // 等同于 var p = new Promise((resolve, reject) => reject('出错了'))

注意:参数会原封不动的传递给后续方法的参数。(不会执行thenable中的then 方法)

done 和 finally

done

Promise对象的回调链,不管以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为Promise内部的错误不会冒泡到全局)。因此,我们可以提供一个done方法,总是处于回调链的尾端,保证抛出任何可能出现的错误。

 
asyncFunc() .then(f1) .catch(r1) .then(f2) .done();

finally

finally方法用于指定不管Promise对象最后状态如何,都会执行的操作。它与done方法的最大区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。

 
helloWorld(true) .then(function () { // run test }) .finally(function(){ // 必然执行 });

Demo实践

多个异步问题

 
function pro(flag) { return new Promise((res, rej) => { if (flag) { res('success') } else { rej('fail') } }) } function pro2() { return new Promise((res, rej) => { setTimeout(function () { console.log('222'); res(); }, 5000); }) } function pro3() { return new Promise((res, rej) => { setTimeout(function () { console.log('333'); res(); }, 1000); }) } function pro4() { return new Promise((res, rej) => { setTimeout(function () { console.log('444'); res(); }, 4000); }) } function pro5() { return new Promise((res, rej) => { setTimeout(function () { console.log('555'); res(); }, 1000); }) } pro(true) .then((res) => { console.log(res); }) .then(pro2) .then(pro3) .then(pro4) .then(pro5) //success 222 333 444 555

单纯的回调,前者return值可以作为后续操作的参数

 
function helloWorld(flag){ return new Promise(function(resolve, reject){ if(flag){ resolve('成功') }else{ reject('失败') } }) }; helloWorld(true).then(function (message) { return message; }).then(function (message) { return message + ' World'; }).then(function (message) { return message + '!'; }).then(function (message) { alert(message); }); // 成功 World! helloWorld(false).then(function (message) { return message; }).then(function (message) { return message + ' World'; }).then(function (message) { return message + '!'; }).then(function (message) { alert(message); }).catch(function(message){ alert(message) }) // 失败

总结

new Promise(fn(resolve, reject)) 接收一个函数
fn(resolve, reject) 两个参数都是函数
.then(fn) 接收一个函数,且then执行后返回一个Promise,所以能够继续then下去
Promisethen接收的函数如同setTimeOut一样“自执行”


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值