当前位置: 首页 > Web前端 > JavaScript

Promise源码渐进解读(四)

时间:2023-03-26 23:16:40 JavaScript

关注前端小鱼,阅读更多原创技术文章回顾:Promise源码渐进解读(一)回顾:Promise源码渐进解读(二)回顾:Promise源码渐进解读(三)完整代码+注意,您可以阅读更多内容以进行比较Athenconcatenation-剩余问题/*尚未实现:不少于2.then()链调用*/newPromise((resolve,reject)=>{resolve(3)})。then((res)=>{/*调用第一个then时,prom为当前then之前返回的合约实例,即resolved合约实例,resolved值为3.PrintselfasPromiseinhandle(){_state:1,_handled:true,_value:3,_deferreds:[]}将继续异步执行处理程序*/returnres}).then((res)=>{/*当第二个then被调用时,prom是当前then之前返回的合约实例是第一个then返回的prom,是一个新的cr吃了和未解决的合同实例。将当前then中生成的Handler实例放入当前then之前返回的合约实例的_deferreds数组中,然后暂停并返回打印selfinhandle()asPromise{_state:0,_handled:false,_value:undefined,_deferreds:[Handler{...}]}*/console.log(res)//不打印res,第二个then及后续的handlers还没有实现})多个then链调用时,从第二个then开始,之前返回的Promise实例都是pending状态的空合约实例,所以将Handler实例放入之前返回的Promise实例的_deferreds数组中。本节将详细讲解handle()和finale()方法,重点讲解Promise实例的_deferreds数组放入Handler实例后的操作。应该反复看handle()-源码终于到了handler()的源码!其实只是比上一节的测试代码改进了一些内容而已。我们主要观察多个then的串联(以2为例)/**handle()方法:核心*参数self:之前then()返回的Promise实例*参数deferred:本次创建的Handler实例*/functionhandle(self,deferred){//console.log(self,'handle')//console.log(deferred)/*deferred是创建的Handler实例Handler{onFulfilled:[Function(anonymous)],//onFulfilledhandler,nullifnotonRejected:[Function(anonymous)],//onRejectedhandler,nullifnonepromise:Promise{//promise属性指向一个新的Promise实例_state:0,_handled:false,_value:undefined,_deferreds:[]}}*//*如果返回的合约实例的解析值为promise类型,_state=3*/while(self._state===3){self=self._value//将解析值赋给返回的合约Example//console.log(self)}/*如果_state=0,现货合约实例处于挂起状态(onResolve或onReject处理程序尚未执行)*//*当链被调用时,secondorlaterthen()之前返回的Promise实例总是一个新的Promise实例,它的_state值为0*/if(self._state===0){self._deferreds.push(deferred)//把Handler实例onthen()之前返回的Promise实例的_deferreds数组,由于前一个Handler实例的promise指向前一个Promise实例,因此前一个Handler实例也会相应受到影响//console.log(self,'push')/*Promise{_state:0,_handled:false,_value:undefined,_deferreds:[Handler{onFulfilled:[Function(anonymous)],onRejected:[Function(anonymous)],promise:[Promise]}]}*/return//这里同步执行暂停,等待异步执行(在上一个Promise的then中执行onResolve)}/*如果不是以上情况,则将当前promise._handled标记为true*/self._handled=true//console.log(self)/**通过事件循环异步处理回调*注意:这里的事件是异步执行的,第二个then会先于这里的方法执行*/Promise._immediateFn(function(){//console.log(deferred,'_immediateFn')//注意:当.then()不少于2个时,上一个.then()生成的Handler实例会有一个promisePromise实例的_deferredspointed指向问题所在(后面的.then()包含onFulfilled或onRejected回调函数,_deferreds不再指向空数组,而是指向包含后者Handler实例的数组)varcb=self._state===1?deferred.onFulfilled:deferred.onRejected//根据最后一次then()之前Promise强度的_state获取onFulfilled或者onRejected处理函数//console.log(cb)/*如果没有onFulfilled或者onRejected回调函数,然后携带当前_value值等待下一个Promise对象的回调*/if(cb===null){//console.log(deferred.promise,self._value);(self._state===1?resolve:reject)(deferred.promise,self._value)/***resolve()或reject方法:等待下一个Promise对象的回调*参数deferred.promise:Handler实例的promise,指向上一个then()的Promise实例*参数self._value:上一个then()之前返回的Promise实例的_value属性值*///resolve(deferred.promise,self._value)//reject(deferred.promise,self._value)return}/*如果有onFulfilled或onRejected回调函数,执行自己的回调*/varrettry{/***cb()方法:执行onFulfilled或onRejectedhandler*参数self._value:returnedbeforethen()Promise实例的解析值/拒绝原因*/ret=cb(self._value)//执行回调并将返回值赋给ret}catch(e){/***reject()方法:处理下一个catch的回调方法*参数deferred.promise:创建的Handler实例的promise属性,指向新的Promise实例*参数e:错误信息*/reject(deferred.promise,e)return}/***resolve()方法:处理下一个then回调方法*参数deferred.promise:Handler实例的promise,指向then()之前的上一个Promise实例*参数ret:执行当前then回调的返回值*///console.log(deferred.promise,ret)resolve(deferred.promise,ret)})}在第二个then之前返回的Promise实例一定是pending状态,所以在第二个then生成的Handler实例会放在第二个then之前返回的Promise实例的_deferreds数组中。还记得Handler构造函数吗?每次then被调用都会生成一个Handler实例,2个then系列会生成2个Handler实例。每个Handler实例的promise指向当前then中生成的Promise实例prom(也就是下一个then之前返回的Promise)实例)但是由于第二个then改变了第二个then之前返回的Promise实例(_deferreds数组是放到Handler实例中),第一个Handler实例也随之变化打开handle()最后的注释console.log(deferred.promise,ret)可以更好的观察到Handler实例的变化。总结起来就是第一个Handler实例的promise属性指向的Promise实例,它的_deferreds数组也被放到了第二个Handler实例中。第二点,在调用handler之后,会再次调用resolve()方法,保证第二个then能拿到第一个then的返回值,记得吗?在resolve()中,为其_state和_value赋值,并调用finale()方法。于是我们来到最终的源码——finale()方法finale()——源码/**finale()方法*参数self:(contract)实例*/functionfinale(self){//console.log(self,'finale')/*如果_state的值为2(Promise执行了reject()方法),并且没有提供回调函数(或者没有实现catch函数),则给出警告*/if(self._状态===2&&self._deferreds.length===0){/***执行Promise构造函数的_immediateFn()方法*参数fn:要执行的w??arning方法*/Promise._immediateFn(function(){/*如果没有处理过,会给出警告*/if(!self._handled){/***执行Promise构造函数的._unhandledRejectionFn()方法*参数self._value:拒绝原因*/Promise._unhandledRejectionFn(self._value)}})}/*循环self._deferreds,为每个项目执行handle()方法*/for(vari=0,len=self._deferreds.length;i{resolve(3)}).then((res)=>{console.log(res)return4}).then((res)=>{console.log(res)return5})根据源码,上面代码的完整调用过程是:newPromise((resolve,reject)=>{resolve(3)})执行newPromise,创建一个Promise实例,返回这个Promise实例执行doResolve(),并执行执行函数(resolve,reject)=>{resolve(3)}同步resolve(3),将Promise实例的_state赋值为1,_value赋值为3执行finale(),将Promise实例的_deferreds赋值给[],赋值为null然后执行返回的Promise实例:Promise{_state:1,_handled:false,_value:3,_deferreds:null}.then((res)=>{console.log(res);return4})执行Promise.prototype.then,创建一个新的Promise实例,并传入一个空方法作为executionhandler函数返回这个新的Promise实例来执行新的Handler,包装当前的onFulfilled处理程序(res)=>{console.log(资源);return4},返回Handler实例执行handle(),传入最后一次then()之前返回的Promise实例并且Handler实例上Promise实例的_state为1,将其_handled赋值为true,执行Promise。_immediateFn(),将当前的onFulfilledhandler放入异步线程1返回Promise实例:Promise{_state:0,_handled:false,_value:undefined,_deferreds:[]}.then((res)=>{console.log(res);return5})执行Promise.prototype.then,创建一个新的Promise实例,传入一个空方法作为executor函数,返回这个新的Promise实例执行新的Handler,包装当前的onFulfilledhandler(res)=>{console.log(res);return5},返回Handler实例执行handle(),传入最后一个then()之前返回的Promise实例,并且Handler实例上前一个Promise实例的_state为0,将这个下一个Hander实例放入它的_deferreds空数组中。return后,因为没有后续的.then(),同步线程挂起之前的Promise实例,变成:Promise{_state:0,_handled:false,_value:undefined,_deferreds:[Handler{}]},Handler是这个Handler实例的重点:由于Handler实例的promise指向.then()中创建的Promise实例(prom),所以之前的Handler实例也会受到影响,它的promise指向Promise实例的_deferreds(也就是之前的Promise实例)也指向[Handler{}]返回异步线程1,执行之前的Handler实例包裹的onFulfilledhandler,打印3,返回4,执行resolve(),传入之前的Handler实例的promise(指向发生变化的Promise实例)和onFulfilled(4)的返回值,将_state将1和_value赋值给4。此时,变更后的Promise实例更新为Promise{_state:1,_handled:false,_value:4,_deferreds:[Handler{}]}执行finale(),传入更新后的Promise,循环_deferreds数组执行handle(),传入更新后的Promise实例和本次Handler实例更新的Promise实例的_state为1,将其_handled赋值为true,执行Promise._immediateFn(),并设置currentonFulfilled处理程序被放置在异步线程2中(嵌套在异步线程1中)。由于没有同步线程,直接进入异步线程2,执行本次Handler实例包装的onFulfilledhandler,打印4,返回5并执行resolve(),传入本Handler实例的promise(不变,initialPromiseinstance)和onFulfilled(5)的返回值,将_state赋值为1,_value赋值为5。此时Promise实例更新为Promise{_state:1,_handled:false,_value:5,_deferreds:[]}执行finale(),传入更新后的Promise,其_deferreds为[],赋值为null,执行结束后返回Promise实例:Promise{_state:0,_handled:false,_value:undefined,_deferreds:[]}再总结一下:newPromise的executor函数是同步的,不管多少个。直到Promise._immediateFn)是同步的,依次执行下面的.then会改变之前返回的Promise实例,从而改变之前生成的Handle实例。同步执行后,先在.thenPromise._immediateFn中执行handle()中的异步方法,开启异步线程,在异步线程结束时,执行resolve()方法,再执行finale()方法。此时传入的Promise实例的_deferreds不再是空数组,而是放入下一个.then中的处理方法再执行handle()方法和其中的Promise._immediateFn再次在异步线程中嵌套一个新的异步线程,直到最终交替执行then和catch的链式调用-阶段测试Promise.resolve(1).catch((err)=>{console.log(3)//不打印,在resolvereturn3后不执行onRejected处理程序}).then((res)=>{console.log(res)//1})Promise.reject(1).then((res)=>{console.log(2)//不打印,rejectreturn2后不执行onResolvedhandler}).catch((err)=>{console.log(err)//1})resolve后不会执行onRejectedhandler,reject后不会执行onResolvedhandler中间的then或catch。没有回调阶段测试newPromise((resolve,reject)=>{resolve(3)}).then()//没有回调,等待下一个Promisecallback.then((res)=>{console.log(res)})newPromise((resolve,reject)=>{reject(4)}).catch()//没有回调,等待下一个Promise的回调.catch((res)=>{console.log(res)})携带当前_value值,等待Promise._immediateFn中下一个Promise对象cb===null的回调handle()方法,根据之前Promise对象的类型(resolve/reject),调用resolve()或reject()方法实现结果汇总实现:multiplechaincallsofthen(catch)AchainofcallswithalternatingthenandcatchAchainofcallswithathenorcatchinthemiddlewithoutacallback代码从本节开始→