APP下载

前端ES6中Promise的执行原理

消息来源:baojiabao.com 作者: 发布时间:2024-11-01

报价宝综合消息前端ES6中Promise的执行原理

Promise的作用

它是异步程式设计的一种方式,它比传统的异步回拨和事件更合理也更优雅!

从Promise的使用中能看出什么?

首先我们手写一个常见的使用方式

//demo1

new Promise(function (resolve, reject) {

resolve('123')

}).then(function (value) {

return value;

}).then(function (value1) {

return value1;

}).catch(function(e) {

return e;

})

从这个demo中就可以看出来,首先需要定义一个Promise的建构函式、then方法以及catch方法。then方法可以传入两个函式作为引数,catch就是then演变而来的(第一个引数传null)。Promise的建构函式有一个函式作为引数,这个函式也有两个引数(resolve,reject)并且它们俩也是函式。

//demo2

Promise = function(fn) {

fn(relsove, reject)

}

relsove = function(val) {

}

reject = function(val) {

}

Promise.prototype.then = function(fn1, fn2){

//fn1 和 fn2都是函式

}

Promise.prototype.catch = function(fn){

this.then(null, fn)

}

以上这段程式码从使用promise的表面就能看出来。

Promise链式呼叫

我们把demo1换一种书写的形式

//demo3

p1 = new Promise(function (resolve, reject) {

resolve('123')

})

p2 = p1.then(function (value) {

return value;

})

p3 = p2.then(function (value1) {

return value1;

})

p4 = p3.catch(function(e) {

return e;

})

从上面的程式码中可以看出来,Promise采用链式呼叫,类似于jquery,无论then还是catch肯定都返回一个promise物件,那么p1、p2、p3、p4返回的promise物件是同一个吗?并不是!!!每次呼叫then方法都会返回一个新的promise物件。

//demo4

noop = function() {

}

Promise.prototype.then = function(fn1, fn2){

return new this.constructor(noop)

}

Promise物件的状态

promise物件存在三种状态

未执行执行完成,此处又分两种//demo5

PENDING = 0 //未执行

FULFILLED = 1 //执行完毕,符合预期

REJECTED = 2 //执行完毕,不符合预期

p.state = 0/1/2

Promise链式呼叫的结果传递

看demo3,除了p1初始化一个promise物件外,p2、p3、p4都各自生成了一个promise物件,每个promise物件除了挂载一个执行状态外,还挂载执行结果、下一个promise物件,以及then中的两个引数函式。

//demo6

p.state //执行状态

p.result //执行结果

p.subscribers = [child, fn1, fn2]

//child 是下一个then生成的promise物件

//fn1 和 fn2 是下一个then的两个引数,catch中fn1=null

child.state //执行状态

child.result //执行结果

child.subscribers = [child1, fn1, fn2]

可以想到只要上一个promise执行完成,就能拿到上一个promise的执行结果和执行状态,就能传给下一级,subscribers会根据上一个promise的执行状态来选择执行fn1还是fn2,然后把上一个promise的执行结果传递给它们其中一个。最后待完成之后,又会通过child寻找下一个child,一层层找下去。

Promise链式呼叫中出现异常

修改demo3

//demo7

p1 = new Promise(function (resolve, reject) {

reject(123)

})

p2 = p1.then(function (value) {

return value;

})

p3 = p2.then(function (value1) {

return value1;

})

p4 = p3.catch(function(e) {

return e+1;

})

p5 = p4.catch(function(value2) {

return value2;

})

我们一般提倡不写then的第二个函式,下面接catch方法,这样看起来更优雅

p1执行后的状态是2,但是p2中的then方法没有第二引数函式,这样的情况是p2的状态和执行结果会被设定为和p1一致,p3也没有第二个引数,它也会跟随p2的状态,直到catch。

//demo8

p1.state = 2

p1.result = 123

p2.state = 2

p2.result = 123

p3.state = 2

p3.result = 123

p4.state = 1

p4.result = 123

p5.state = 1

p5.result = 124

执行catch的时候,结果符合预期没有发生异常,所以呢,这个p4的状态又变成了1,下面的p5肯定也是1,之前的p2、p3中的状态和结果会和它们的上一级保持一致,虽然它们的then方法的第一个引数没有执行。

为什么Promsie中异步的情况下链式也能正常执行

存在异步的情况

看demo1

1、无论是new一个promise物件还是后面执行then和catch方法都是同步的,它们都是在做初始化的工作;

2、其中重要的就是每次执行一个then都会建立一个新的promise物件作为上一个promise物件的child,上一个promise物件作为parent,而child是否挂载到parent上作为它的一个属性取决于建立child的时候parent的状态state还是不是为0,如果parent已经执行完成,状态变成了1或者2,child可以直接拿到parent的结果,那么就不需要把child挂载到parent上,反之需要!

3、当开关->parent->child->child->.....这样的链路建立以后,无论什么时候开启开关,它都会像多米诺骨牌一样向后依次执行,而resolve/reject就是这个开关

为什么Promise中能抓住异常并把异常传递到catch中处理

无论是promise建构函式中引数函式,还是then中的引数函式,它们都是在一个try catch中执行的,catch中会用reject处理

//demo9

Promise = function(fn) {

try {

fn(relsove, reject)

} catch(e) {

reject(e)

}

}

relsove = function(val) {

}

reject = function(val) {

}

Promise.prototype.then = function(fn1, fn2){

//fn1 和 fn2都是函式

try {

fn12(value)

} catch(e) {

reject(e)

}

}

异步中的异常是抓不住的!

总结

本来想写全的,但是发现越写东西越多,这篇文章就分析到这吧,后面再补充!很多东西讲浅了怕说的不全面,讲深了又怕描述不清楚!

喜欢我的文章就关注我吧,有问题可以发表评论,我们一起学习,共同成长!

2019-07-11 01:48:00

相关文章