使用类型来实现一个简易版的Promise,仅供参考!
首先定义一个Executor类型用于表示Promise构造方法的参数,即resolve和reject两个回调函数
type Executor<T>=(resolve:(result:T)=>void,reject:(error?:unknown)=>void)=>void
TS内置的Promise因为reject函数可以接收一个或0个参数,所以在实现的时候也就将error定义为可选参数。
接下来,定义Promise需要的三个状态:
type State="pending" | "rejected" | "fulfilled"
下面开始描述Promise的内部结构:
class Promise<T extends unknown>{
private PromiseState:State="pending" //表示当前期约状态,默认待定态
private PromiseResult?:T=undefined //期约值
public constructor(fn:Executor<T>){
fn(this.resolve.bind(this),this.reject.bind(this))
}
}
应该很好理解吧?构造方法接收的参数就是resolve和reject回调函数,接收之后就开始立即执行,下面是private resolve方法和private reject 方法的具体实现:
private resolve(result:T):void{
if(this.PromiseState==="rejected"){ //如果已经执行了reject,则不再改变期约状态
return
}
this.PromiseState="fulfilled" //解决
this.PromiseResult=result
}
private reject(error?:any):void{
if(this.PromiseState==="fulfilled"){ //如果已经执行了resolve,则不再改变期约状态
return
}
this.PromiseState="rejected" //拒绝
this.PromiseResult=error
console.error(`Uncaught (in promise) ${error}`
}
上面两个方法,保证了期约状态只会改变一次,即从 pending态=>fulfilled态 或 pending=>rejected态,符合TS Promise的定义
最后来看看then和catch方法:
public then<U>(fn:(result?:T)=>Promise<U>):Promise<U>{
if(this.PromiseState!=="fulfilled"){
return this as Promise<U>
}
return fn(this.PromiseResult)
}
public catch<U>(fn:(result?:any)=>Promise<U>):Promise<U>{
if(this.PromiseState!=="rejected"){
return this as Promise<U>
}
return fn(this.PromiseResult)
}
then和catch方法允许用户传入一个回调函数,并且该回调的返回类型是另一个类型的期约,比如下面的例子:
let promise:Promise<number>=new Promise((r,j)=>{
r(1) //传入解决值的类型为number
})
promise.then((v)=>{
console.log(v) // 1
return new Promise<string>((r,j)=>{
r('Hello') //返回新类型期约字符串
})
}).then((v)=>{
console.log(v) //'Hello'
return promise
})
最后测试发现没啥大问题,就是每次调用catch和then方法都要显式的返回一个期约,比较繁琐,但是我又不愿让程序变得any起来,于是做了些平衡。最后这个简易版的Promise看上去有那么回事吧~