当前位置: 首页 > 科技观察

Promise学习笔记(三):源码core.js解析(上)

时间:2023-03-20 17:00:38 科技观察

源码阅读阶段先了解Promise的基础知识,想快速了解的可以直接跳到下一题。这部分将根据理解不断修改。Promise(fn)functionnoop(){}/*空函数,用于判断传入Promise构造函数的函数是否为空函数,如果为空函数,则构造一个promise对象并初始化状态为pending,finalvalue为null,回调状态为0且queue为null。*/varLAST_ERROR=null;//在Promise内部记录一个错误***varIS_ERROR={};//空对象,表示发生了错误module.exports=Promise;//将模块接口暴露为PromisefunctionPromise(fn){if(typeofthis!=='object'){thrownewTypeError('Promisesmustbeconstructedvianew');}if(typeoffn!=='function'){thrownewTypeError('Promiseconstructor\'sargumentisnotafunction');}this._deferredState=0;this._state=0;//Promise状态this._value=null;//resolve返回的结果this._deferreds=null;if(fn===noop)return;doResolve(fn,this);//处理函数}Promise._onHandle=null;Promise._onReject=null;Promise._noop=noop;在原文中是指带_前缀的变量在构造时会转成(_randomnumber)形式来混淆和防止从被使用。下面列出了需要说明的重要变量。*_defferedState=0表示_deferreds的类型,0表示null,1表示单个handler(后述),2表示多个deferreds(数组)*_state=0promise状态,0为pending,1为fulfilled,2为rejected,3*_value=nullresolve返回结果,也就是我们所说的最终值/拒绝*_deferreds=null表示单个或多个处理程序(稍后介绍)doResolve(fn,this)比较用大家都见过的函数doResolve(fn,this);,下面就是我们初始化一个Promise的时候要做的事情。在看这个功能之前,我们先要明白源码是类似于工具函数一样的功能。//获取then方法,没有then方法识别错误functiongetThen(obj){try{returnobj.then;}catch(ex){LAST_ERROR=ex;returnIS_ERROR;}}//内部捕获错误,单参数函数functiontryCallOne(fn,a){try{returnfn(a);}catch(ex){LAST_ERROR=ex;returnIS_ERROR;}}//内部捕获错误,两个参数functiontryCallTwo(fn,a,b){try{fn(a,b);}catch(ex){LAST_ERROR=ex;returnIS_ERROR;}}接下来我们直接跳转到doResolve(fn,promise):functiondoResolve(fn,promise){//传入的参数是一个函数,一个promiseobjectvardone=false;//保证了规范中提到的一次性varres=tryCallTwo(fn,function(value){//看到没,用来捕获错误if(done)return;//不用多说这里,为了保证两个函数中只有一个运行并且只运行一次done=true;resolve(promise,value);//稍后再分析},function(reason){if(done)return;done=true;reject(promise,reason);//稍后分析});if(!done&&res===IS_ERROR){done=true;reject(promise,LAST_ERROR);//稍后再分析}}这是我们的doResolve函数,可以看到它只是一个中间件。它的作用是解决传入函数的错误问题并拒绝。重点是调用我们熟悉的两个函数,resolve()和reject()。resolve()和reject()在这个函数中,我们发现了两个新东西,resolve()和reject(),这两个函数看名字就知道是什么了,先来看看reject()吧!functionreject(self,newValue){//两个参数,从doResolve我们可以知道self是一个promise对象,newValue是拒绝的原因self._state=2;//状态变成了被拒绝的self._value=newValue;//promise中的result变成rejectionif(Promise._onReject){//在core.js中为null,所以可能用于其他功能。我们跳过Promise._onReject(self,newValue);}finale(self);//又出现了一个新的函数。}reject()函数传入一个promise对象和一个拒绝的原因。该函数所做的是将promise的状态更改为rejected并更改promise的值。然后调用finale()函数。可以看到新的函数finale()出现了,把被拒绝的promise对象传给了它。但是让我们先看看resolve()!functionresolve(self,newValue){//这里写的其实是按照规范处理的过程/*PromiseResolutionProcedure:https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure*/if(newValue===self){//如果传入的值等于自己,则抛出错误returnreject(self,newTypeError('Apromisecannotberesolvedwithitself.'));}if(//值为一个objectorafunctionnewValue&&(typeofnewValue==='object'||typeofnewValue==='function')){varthen=getThen(newValue);//获取then函数中的值if(then===IS_ERROR){//没有then,reject返回reject(self,LAST_ERROR);}if(//存在且原值为promise对象then===self.then&&newValueinstanceofPromise){//同步两个promise,改变状态传入的承诺传递并使用承诺对象newValue作为承诺值,然后结束并退出function.self._state=3;self._value=newValue;finale(self);return;}elseif(typeofthen==='function'){//如果then的值不是promise,而是一个函数(thenable)doResolve(then.bind(newValue),self);//这里可以看之前的博文,里面有说明这种情况,doResolvethefinalvalue自己获取一个新值作为newFinalvalue.return;}}self._state=1;//promisestateisfulfilledself._value=newValue;//传值finale(self);//finale}在resolve()中,我们仍然传入一个promise对象和值(finalvalue),函数内部通过标准判断(详见学习笔记(2):specification),执行[[Resolve]]操作,***改变promise对象的状态为fulfilled并改变它的final值,调用finalefinale()我们可以分析一下finale(),毕竟我们所有的核心函数都指向它!functionfinale(self){//传入一个promise对象if(self._deferredState===1){//判断deferreds是单句柄(self,self._deferreds);//传入promise对象和promiseobject_deferredsself._deferreds=null;//让deferreds为null}if(self._deferredState===2){//判断deferreds是一个数组for(vari=0;i