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

从头实现一个Promise_0

时间:2023-03-26 22:05:43 JavaScript

一、Promise生成背景及规范众所周知,Promise是ES6引入的一个新特性,旨在解决回调地狱。下面是一个简单的例子:控制接口调用顺序:apiA-->apiB-->apiC。业务复杂,开发商会分流。后人在此祭奠老前辈。//回调地狱apiA({handleSuccess(resA){apiB({handleSuccess(resB){apiC({handleSuccess(resC){}})}})}})所以Promise/A+规范应运而生,ES6的Promise是根据规范开发。2、同步Promise读取规范可以得到如下基本要求:Promise有三种状态:pending(等待状态)、fulfilled(成功状态)、rejected(失败状态)pending是初始状态,可以转化为fulfilled和rejectedsuccessful当它失败时,它不能转移到其他状态,并且必须有一个不变的值(值)。当它失败时,不能转移到其他状态,必须有一个不可改变的原因(reason)newPromise(executor=(resolve,reject)=>{resolve(value)}),resolve(value)setthestatetofulfillednewPromise(executor=(resolve,reject)=>{reject(reson)}),reject(reson)如果executor运行异常则设置状态为rejected执行reject()thenable:then(onFulfilled,onRejected)onFulfilled:statusisfulfilled,executeonFulfilled,passinvalueonRejected:statusisrejected,executeonRejected,passinreason//1.Promise有三种状态:pending(等待状态),fulfilled(成功状态),rejected(失败状态)constSTATUS_PENDING='pending'constSTATUS_FULFILLED='fulfilled'constSTATUS_REJECTED='rejected'classmyPromise{constructor(executor){//pending是初始状态,可以转换为fulfilled和rejectedthis.status=STATUS_PENDINGthis.value=''//3this.reason=''//4letresolve=value=>{//5.if(this.status===STATUS_PENDING){this.status=STATUS_FULFILLEDthis.value=value}}letreject=reason=>{//6.if(this.status===STATUS_PENDING){this.status=STATUS_REJECTEDthis.reason=reason}}//7.try{executor(resolve,reject);}抓住(错误){拒绝(错误);}}//8.then(onFulfilled=()=>{},onRejected=()=>{}){//8.1if(this.status===STATUS_FULFILLED){onFulfilled(this.value)}//8.2if(this.status===STATUS_REJECTED){onRejected(this.reason)}}}newmyPromise(resolve=>{console.log('beforeresolve')resolve(1)}).then(res=>{console.log(res)})newmyPromise((resolve,reject)=>{console.log('beforereject')reject('rejecterror')}).then(res=>{console.log(res)},错误=>{console.log(error)})3.异步PromisenewmyPromise(resolve=>{console.log('beforeresolve')setTimeout(()=>{resolve(1)},1000)}).then(res=>{console.log(res)})promise的状态只能在resolve或rejects时改变。当同步代码执行到then回调时,promise的状态仍然是pending。细节不符合我们的预期。如果是你,你会如何解决这个问题?比如你在处理一堆事情(pendingstatus),然后(then),老板说:你一秒做完你在做的事情到我办公室来,做不完就滚蛋.如果怕忘记,一般会用list来记录onResolvedCallbacks=['做完手头的事情,去老板办公室'],onRejectedCallbacks=['做不完,滚'],看1秒后完成结果,然后选择下一步。改进后的代码如下:参考前端高级面试题的详细答案constSTATUS_PENDING='pending'constSTATUS_FULFILLED='fulfilled'constSTATUS_REJECTED='rejected'classmyPromise{constructor(executor){this.status=STATUS_PENDINGthis.value=''this.reason=''//成功存储数组this.onResolvedCallbacks=[];//失败的存储方法数组this.onRejectedCallbacks=[];letresolve=value=>{if(this.status===STATUS_PENDING){this.status=STATUS_FULFILLEDthis.value=value//pending->fulfilledExecutethis.onResolvedCallbacks.forEach(fn=>fn())}}letreject=reason=>{if(this.status===STATUS_PENDING){this.status=STATUS_REJECTEDthis.reason=reason//pending->rejected执行this.onRejectedCallbacks.forEach(fn=>fn());}}try{executor(resolve,reject);}抓住(错误){拒绝(错误);}}then(onFulfilled=()=>{},onRejected=()=>{}){if(this.status===STATUS_FULFILLED){onFulfilled(this.value)}if(this.status===STATUS_REJECTED){onRejected(this.reason)}//忙碌状态,首先记录老板点了什么if(this.status===STATUS_PENDING){//onFulfilled传给成功的数组this.onResolvedCallbacks.push(()=>onFulfilled(this.value))//onRejected传给失败的arraythis.onRejectedCallbacks.push(()=>onRejected(this.reason))}}}//异步newmyPromise((resolve,reject)=>{console.log('老板说:一秒完成任务Go到我办公室,做不完就滚')setTimeout(()=>{if(false){//小妾做不完resolve('做完手头的事,就去老板家office')}else{reject('不能完成,滚出去')}},1000)}).then(res=>{console.log(`1slater:${res}`)},error=>{console.log(`1slater:${error}`)})//老板说:一秒钟做完你现在的事来我办公室,做不完,getout//1秒后:如果做不完就滚出去4.newPromise().then().then()...这个思路挺简单的,就是then的返回值function是另一个Promise实例根据规范修改如下:constPENDING='pending'constFULFILLED='fulfilled'constREJECTED='rejected'functionresolvePromise(promise2,x,resolve,reject){//循环引用错误if(x===promise2){//拒绝错误returnreject(newTypeError('Chainingcycledetectedforpromise'));}//防止多次调用letcalled;//x不为空并且x是一个对象或函数if(x!=null&&(typeofx==='object'||typeofx==='function')){try{//A+规定then声明then=x的方法letthen=x.then;//如果then是一个函数,它默认是一个promiseif(typeofthen==='function'){//让then执行第一个参数是this后跟一个成功的回调和一个失败的回调then.call(x,y=>{//success和Failure只能调用一个if(called)return;called=true;//resolve的结果还是promise,然后继续解析resolvePromise(promise2,y,resolve,reject);},err=>{//只有成功和失败才能调用if(called)return;called=true;reject(err);//failonfailure})}else{resolve(x);//直接succeed就可以了}}catch(e){//if(called)return也是失败;称为=真;//如果取then有错误,就不要继续执行reject(e);}}else{解决(x);}}classPromise{constructor(executor){this.state=PENDINGthis.value=''this.reason=''//成功存储数组this.onResolvedCallbacks=[];//失败的存储方法数组this.onResolvedCallbacks=[];letresolve=value=>{if(this.state===PENDING){this.state=FULFILLEDthis.value=value//pending->fulfilledExecutethis.onResolvedCallbacks.forEach(fn=>fn())}}letreject=reason=>{if(this.state===PENDING){this.state=REJECTEDthis.reason=reason//pending->rejected根据异常列表执行this.onRejectedCallbacks.forEach(fn=>fn());}}try{executor(resolve,reject);}抓住(错误){拒绝(错误);}}then(onFulfilled,onRejected){//onFulfil如果led不是函数,忽略onFulfilled直接返回值onFulfilled=typeofonFulfilled==='function'?onFulfilled:值=>值;//如果onRejected不是函数,则忽略onRejected并抛出错误onRejected=typeofonRejected==='function'?onRejected:错误=>{抛出错误};letpromise2=newPromise((resolve,reject)=>{if(this.state===FULFILLED){//异步解析://onRejected返回一个普通值,如果直接等于value=>value当它fails,//接下来会运行到onFulfilledthen,setTimeout(()=>{try{letx=onFulfilled(this.value);resolvePromise(promise2,x,resolve,reject);}catch(e){reject(e);}},0);};if(this.state===REJECTED){setTimeout(()=>{try{letx=onRejected(this.reason);resolvePromise(promise2,x,resolve,reject);}catch(e){reject(e);}},0);};if(this.state===PENDING){this.onResolvedCallbacks.push(()=>{setTimeout(()=>{try{letx=onFulfilled(this.value);resolvePromise(promise2,x,resolve,reject);}catch(e){拒绝(e);}},0);});this.onRejectedCallbacks.push(()=>{setTimeout(()=>{try{letx=onRejected(this.reason);resolvePromise(promise2,x,resolve,reject);}catch(e){reject(e);}},0)});};});回报承诺2;}}newPromise(resolve=>{console.log(0)setTimeout(()=>resolve(1),3000)}).then(res=>{console.log(res)returnnewPromise(resolve=>{console.log(2)setTimeout(()=>{resolve(3)},3000)})}).then(res=>{console.log(res)})5.抓住、解决、拒绝,种族和所有1。catch(specialthenmethod)catch(fn){returnthis.then(null,fn)}2.resolve(解析一个值)Promise.resolve=val=>newPromise(resolve=>resolve(val))3.reject(拒绝一个值)Promise.reject=val=>newPromise((resolve,reject)=>reject(val))4.racePromise.race([p1,p2,p3])whichresult快速获取就返回结果,不管结果本身是成功状态还是失败状态Promise.race=promises=>newPromise((resolve,reject)=>promises.forEach(pro=>pro.then(resolve,reject)))5.allPromise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值不同。成功时返回结果数组,失败时返回最先被拒绝的值。Promise.all=function(promises){returnnewPromise((resolve,reject)=>{letindex=0;letresult=[];if(promises.length===0){resolve(result);}else{functionprocessValue(i,data){result[i]=data;if(++index===promises.length){resolve(result);}}for(leti=0;i{processValue(i,data);},(err)=>{reject(err);return;});}}});}本文旨在记录学习过程,通过手敲代码加深印象