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

Promise-polyfill源码分析

时间:2023-03-27 15:22:57 JavaScript

Promise是一个JavaScript异步实现。Promise对象内部是异步操作的状态(成功或失败),以及返回值。在日常的开发过程中,使用频率最高的异步方案也是Promise。因此,为了对Promise原理有更深入的理解,有必要阅读promisepolyfill库promise-polyfill的源码。下面将详细分析promise-polyfill的源码。由于promise-polyfill源码是基于ES5规范编写的,相对于ES6+规范,代码不够简洁直接。为此,下面的源码分析将以ES6+代码为代表。Promise构造函数初始化对象数据并执行执行器。classCustomPromise{constructor(executor){if(typeofexecutor!=='function')thrownewTypeError('notafunction')//0-pending//1-fulfilled/noObject&noFunction//2-rejected//3-fulfilled/CustomPromisethis._state=0//标记当前promise实例是否被处理过this._handled=false//记录当前promise的值this._value=undefined//存放then方法中注册的函数this._deferreds=[]doResolve(executor,this)}}/**执行promise_executor**1.提供两个函数参数给executor,让它有选择地执行resolve或reject*2.使用done保证resolve和reject只执行一次*3.执行器函数执行过程中如果出错,立即调用reject*/constdoResolve=(executor,self)=>{letdone=falsetry{executor((value)=>{if(完成)returndone=trueresolve(self,value)},(reason)=>{if(done)returndone=truereject(self,reason)})}catch(ex){if(done)returndone=truereject(self,ex)}}/**执行resolve,执行状态转换**1.newValue!==self*2.newValueinstanceOfCustomPromise,self._state=3,self_value=newValue*3.typeofnewValue.then==='function',promise_executor->newValue.then*4.newValueisotherValue,self._state=1,self_value=newValue*5.ifcodeerror,reject(self,error)*/constresolve=(self,newValue)=>{try{if(newValue===self)thrownewTypeError('Apromisecannotberesolvedwithitself.')if(newValueinstanceofCustomPromise){self._state=3self._value=newValuefinale(self)}elseif(typeofnewValue?.then==='function'){doResolve(bind(then,newValue),self)}else{self._state=1self._value=newValuefinale(self)}}catch(e){reject(self,e)}}/**执行reject,执行状态转换*/constreject=(self,newValue)=>{self._state=2self._value=newValuefinale(self)}/**resolve或者reject之后的最终函数,主要处理_deferreds**1.如果状态为rejected,deferreds为空,则打印错误信息*2.依次执行deferred*/constfinale=(self)=>{//如果状态为rejected,deferreds为空,打印一个错误信息if(self._state===2&&self._deferreds.length===0&&!self._handled){CustomPromise._immediateFn(()=>{CustomPromise._unhandledRejectionFn(self._value)})}//依次执行deferredself._deferreds.forEach((deferred)=>handle(self,deferred))self._deferreds=null}/**handledeferred**1.如果_value为3,则遍历self*2.如果status为pending,进入deferred3.根据_state将onFulfilled或onRejected赋值给callback*3.1如果callback不是函数,则将_value延迟到deferred.promise._value*3.2否则,将callback的执行结果赋值给deferred.promise。_value*/consthandle=(self,deferred)=>{//不断遍历self直到self._state不为3,即self._value不是promisewhile(self._state===3)self=self._value//self._state当挂起时,deferred入队if(self._state===0){self._deferreds.push(deferred)return}self._handled=trueCustomPromise._immediateFn(()=>{constcallback=self._state===1?deferred.onFulfilled:deferred.onRejectedif(callback===null){//回调没有函数,所以self._valuewillbeposted;(self._state===1?resolve:reject)(deferred.promise,self._value)return}//回调执行结果完成,除非执行过程中出现错误letrettry{ret=callback(self._value)}catch(e){reject(deferred.promise,e)return}resolve(deferred.promise,ret)})}then将then函数中的onFulfilled和onRejected挂载到deferred对象上,决定立即执行根据\_state或插入\_deferreds等待执行。classCustomPromise{/**创建一个Promise对象*根据self._state选择性的执行resolve或reject*返回Promise对象*/then(onFulfilled,onRejected){constprom=newthis.constructor(()=>{})handle(this,newHandler(onFulfilled,onRejected,prom))returnprom}}/**创建延迟对象**对象包含:onFulfilled,onRejected,promise*/classHandler{constructor(onFulfilled,onRejected,promise){this.onFulfilled=typeofonFulfilled==='函数'?onFulfilled:nullthis.onRejected=typeofonRejected==='function'?onRejected:nullthis.promise=promise}}catchcatch方法是then(null,onRejected)的语法糖。classCustomPromise{catch(onRejected){returnthis.then(null,onRejected)}}finally无论promise对象的状态如何,finally回调函数都会被执行。classCustomPromise{/**不管成功还是拒绝,finally的回调函数都要执行。*和_value和_state将被推迟。*/finally(callback){constconstructor=this.constructorreturnthis.then((value)=>{callback()returnvalue},(reason)=>{callback()returnconstructor.reject(reason)})}}resolveclassCustomPromise{/**静态解析方法返回一个CustomPromise对象*/staticresolve(value){if(value&&typeofvalue==='object'&&value.constructor===CustomPromise)returnvaluereturnnewCustomPromise((resolve)=>{resolve(value)})}}rejectclassCustomPromise{/**静态拒绝方法返回一个CustomPromise对象*/staticreject(value){returnnewCustomPromise((resolve,reject)=>{reject(value)})}}all传入的参数是一个可迭代对象。如果对象元素状态为fulfilled,则按顺序返回每个元素的结果。如果对象元素状态为rejected,则返回该元素的拒绝结果。classCustomPromise{staticall(list){returnnewCustomPromise((resolve,reject)=>{constlen=list.lengthconstresult=Array(len).fill(undefined)letcount=0constresolver=(i)=>{return(value)=>{result[i]=valueif(++count===len)resolve(result)}}for(leti=0;i{constlen=list.lengthfor(leti=0;i{constlen=list.lengthconstresult=Array(len).fill(undefined)letcount=0constresolver=(i)=>{return(value)=>{result[i]={status:'fulfilled',value}if(++count===len)resolve(result)}}constrejecter=(i)=>{return(reason)=>{result[i]={status:'rejected',reason}if(++count===len)resolve(result)}}for(leti=0;i{fn()hiddenDiv=null}).observe(hiddenDiv,{attributes:true})hiddenDiv.setAttribute('i','1')}}实际上应用promiseAllThrottled以节流方式调用异步函数,默认并发数为3constpromiseAllThrottled=(iterable:(()=>Promise)[],concurrency=3)=>{constpromises:Promise[]=[]constenqueue=(current=0,queue:Promise[]=[]):Promise=>{//如果完成则返回if(current===iterable.length)returnPromise.resolve()//从集合中取出一个promiseconstpromise=iterable[current]constactivatedPromise=promise()//将promise添加到最终结果数组promises.push(activatedPromise)//将当前激活的promise添加到队列中,并在完成后将其删除constautoRemovePromise=activatedPromise.then()=>{//删除完成后从队列中承诺constremoveIndex=queue.indexOf(autoRemovePromise)if(removeIndex>-1)queue.splice(removeIndex,1)returntrue})//添加承诺到队列queue.push(autoRemovePromise)//if队列长度>=并发,wai一个承诺在添加更多之前完成。constreadyForMore=queue.length<并发?Promise.resolve():Promise.race(queue)返回readyForMore.then(()=>enqueue(current+1,queue))}returnenqueue().then(()=>Promise.all(promises))}//testconstrequests=Array(10).fill('').map((_,i)=>()=>newPromise((resolve,reject)=>{setTimeout(()=>{resolve(`任务#${i}`)},1000)}))promiseAllThrottled(requests,3).then((arg)=>console.log(`finished${newDate()}${arg}`))。catch((error)=>console.error('Oopssomethingwentwrong',error))基础;欲走远方,必挖其源。短短的两百行代码,把promise的所有特性都解释清楚了,日常开发中遇到的promise问题顿时变得清晰起来。