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

用TS实现Promise(官方测试工具测试通过)

时间:2023-03-26 20:37:02 JavaScript

相关链接Promises/A+规范(原文)Promises/A+规范(翻译)TS实现Promise相关api代码地址本文代码实现PromiseenumStates{PENDING="pending",/***PENDING状态。此时,Promise的结果处于待定状态。不知道会被解决还是被拒绝。*只有当Promise的状态为PENDING时,resolve和reject函数才能进行一系列操作,否则只会抛出错误。**/FULFILLED="fulfilled",/***FULFILLED状态,表示此时Promise已经解决,“promisefulfilled”。*当Promise的状态为FULFILLED时,可以直接将then方法传入的onFullfilled函数加入微任务队列;*如果Promise当前状态为PENDING,onFullfilled函数只有成功后才能加入回调函数队列。**/REJECTED="rejected",/***REJECTED状态,表示此时Promise已经被拒绝,*当Promise状态为REJECTED时,可以直接将then方法中传入的onRejected函数添加到microtask中队列;*如果当前Promise的状态为PENDING,onRejected函数失败时只能加入回调函数队列。**/}相关类型定义interfaceResolve{(value:T|PromiseLike):void;}interfaceReject{(reason?:any):void;}interfaceExecutor{(resolve:Resolve,reject:Reject):void;}/***Promises/A+只是一个规范,任何能够通过测试的Promise实现都会被这个规范认可,一些库和框架会实现自己的Promise,而不是使用原生的ES6Promise,这使得无法直接使用pinstanceofPromise来识别Promise类型。*因此,Promise的识别是基于ducktypingdetection,只要是thenable对象(即定义了then方法的对象),都会被识别为Promise。*同样,下面的resolvePromise函数的参数x是PromiseLike类型,而不是Promise类型。**/interfacePromiseLike{then(onFulfilled?:((value:T|PromiseLike)=>TResult1|PromiseLike)|undefined|null,onRejected?:((reason:any)=>TResult2|PromiseLike)|undefined|null):PromiseLike;}MyPromise类及其构造函数Promise接收一个执行函数作为参数,执行函数的两个参数(resolve,reject)由Promise内部定义。类MyPromise{私有状态:States=States.PENDING;//Promise的状态privateonFulfilledCbs=[]as(()=>void)[];//成功回调函数privateonRejectedCbs=[]as(()=>void)[];//privatevalue失败时的回调函数!:T|PromiseLike;//Promise传递的值是合法的JavaScript值privatereason:any;//指示Promise失败原因的值constructor(executor:Executor){try{//作为参数传递给Promise的执行器函数将立即被调用executor(this.resolve,this.reject);}抓住(e){这个。拒绝(e);}}resolve:Resolve=(value:T|PromiseLike)=>{try{//由于js没有提供直接用来创建微任务的API,所以这里使用setTimeout来模拟创建微任务setTimeout(()=>{if(this.state===States.PENDING){/***只有当Promise处于PENDING状态时,才会执行resolve方法的实际逻辑。*resolve方法将执行以下操作:*1.将Promise的状态更新为FULFILLED;*2.将resolve接受的值赋值给Promise的值;*3.执行onFulfilledCbs队列中的所有回调函数并清空队列。**/this.state=States.FULFILLED;this.value=值;this.onFulfilledCbs.forEach((fn)=>fn());this.onFulfilledCbs=[];}});}catch(e){this.reject(e);}};reject:Reject=(reason:any)=>{try{//使用setTimeout模拟创建微任务setTimeout(()=>{if(this.state===States.PENDING){/***实际逻辑reject方法仅在Promise处于PENDING状态时执行。*reject方法会做以下事情:*1.将Promise的状态更新为REJECTED;*2.将reject接受的reason值赋值给Promise的reason;*3.执行onRejectedCbs队列中的所有回调函数,并清空队列。**/this.state=States.REJECTED;this.reason=原因;this.onRejectedCbs.forEach((fn)=>fn());this.onRejectedCbs=[];}});}catch(e){this.reject(e);}};}then方法then方法接收两个可选参数,分别是Promise成功和失败的回调函数。这两个函数不会立即调用,具体见代码注释。然后(onFulfilled?:((value:T|PromiseLike)=>TResult1|PromiseLike)|undefined|null,onRejected?:((reason:any)=>TResult2|PromiseLike)|undefined|null):MyPromise{//为了保证onFulfilled和onRejected是函数类型,需要进行类型转换。onFulfilled=typeofonFulfilled===“功能”?onFulfilled:(val:T|PromiseLike)=>valasany;onRejected=typeofonRejected===“功能”?onRejected:(r:any)=>{抛出r;};//then方法的返回值是一个新的Promise,这就是为什么Promise可以被链接起来的原因constpromise2=newMyPromise((resolve:Resolve,reject:Reject)=>{if(this.state===States.FULFILLED){//Promise已经是FULFIILED状态,将onFulfilled放入微任务队列执行.setTimeout(()=>{try{letx=onFulfilled!(this.value);this.resolvePromise(promise2,x,resolve,reject);}catch(e){reject(e);}});}elseif(this.state===States.REJECTED){//Promise已经处于REJECTED状态,将onRejected放入微任务队列中执行。setTimeout(()=>{try{letx=onRejected!(this.reason);this.resolvePromise(promise2,x,resolve,reject);}catch(e){reject(e);}});}elseif(this.state===States.PENDING){/***Promise还处于PENDING状态,还不能处理回调函数,所以直接将回调函数添加到对应的回调队列中。*注意在resolve中调用回调函数是在microtask中进行的,所以这里不需要创建microtask。**/this.onFulfilledCbs.push(()=>{try{letx=onFulfilled!(this.value);this.resolvePromise(promise2,x,resolve,reject);}catch(e){reject(e);}});this.onRejectedCbs.push(()=>{try{letx=onRejected!(this.reason);this.resolvePromise(promise2,x,resolve,reject);}catch(e){reject(e);}});}});returnpromise2;}resolvePromisemethodresolvePromise(promise:MyPromise,x:T|PromiseLike,resolve:Resolve,reject:Reject){/***由于then的返回值method是一个Promise,如果then方法的回调函数也返回一个Promise,就会造成Promise嵌套,所以需要一个函数来处理then方法回调函数的返回值,resolvePromise就是函数。*@parampromisethen方法返回值*@paramxthen回调函数返回值**///防止循环引用if(promise===x){conste=newTypeError("TypeError:Circularreference");拒绝(e);}让叫=false;//防止resolve和reject被多次调用if(x&&(typeofx==="object"||typeofx==="function")){try{constthen=(xasPromiseLike)。然后;//如果x是一个thenableif(typeofthen==="function"){then.call(x,(y:T|PromiseLike)=>{if(called)return;called=true;//直到resolved对象不再thenable,取出valuethis.resolvePromise(promise,y,resolve,reject);},(r:any)=>{if(called)return;领导=真;拒绝(r);});}else{解决(x);}}catch(e){如果(调用)返回;称为=真;拒绝(e);}}else{解决(x);}}测试过程测试工具文档:Promises/A+ComplianceTestSuite为了使用官方工具进行测试,需要在程序最后添加如下代码://@ts-ignoreMyPromise.deferred=function(){让延迟:任何={};deferred.promise=newMyPromise((resolve,reject)=>{deferred.resolve=resolve;deferred.reject=reject;});returndeferred;};//@ts-ignoreexport=MyPromise;编译ts代码运行jstscpromise.ts测试npxpromises-aplus-testspromise.js测试结果:参考Promise源码实现(完全符合Promise/A+规范)实现一个TS版本,Promise《你不知道的 JavaScript 中卷》符合Promise/A+规范