前言:Promise作为解决异步问题的一种方案,成功替代了以往的callback回调函数,在如今的开发中广泛使用,所以它的实现原理更需要掌握。
Promise分为三种状态,分别是:
- pedding:进行中
-
fulfilled:成功
-
rejected:失败
Promise状态一旦确定,变为fulfilled或rejected后,将不可更改;抱着这样的思路,我们将实现一个基础功能的Promise。
实现思路:
1、首先Promise是一个类,它接收一个执行器executor(函数),并且这个函数会立即执行;
2、执行器executor接收两个回调函数作为参数,分别代表resolve与reject;
3、解决异步问题:存储then中的回调函数,当resolve或reject触发后,再依次执行;
4、then中的返回值会作为下个then回调函数的参数;
按照上面思路,代码实现如下:
class YPromise{
// Promise的三种状态,pedding-> fulfilled,pedding-> rejected,不可逆
static PEDDING = 'pedding'
static FULFILLED = 'fulfilled'
static REJECTED = 'rejected'
// 成功状态保存值
#value = null
// 失败状态保存值
#reason = null
constructor(callback){
try {
this.status = 'pedding'
// 保存成功回调
this.fulfilledCallbacks = []
// 保存失败回调
this.rejectedCallbacks = []
callback(YPromise.resolve.bind(this),YPromise.reject.bind(this))
} catch (error) {
YPromise.catch(error)
}
}
static resolve(res){
if(this.status === YPromise.PEDDING || this.status === YPromise.FULFILLED){
this.status = YPromise.FULFILLED
this.value = res
queueMicrotask(() => {
this.fulfilledCallbacks.forEach(fn => {
let res = fn(this.value)
res && (this.value = res)
})
})
}
}
static reject(err){
if(this.status === YPromise.PEDDING){
this.status = YPromise.REJECTED
this.reason = err
queueMicrotask(() => {
this.rejectedCallbacks.forEach(fn => fn(this.reason))
})
}
}
then(resolveFn,rejectFn){
resolveFn = typeof resolveFn === 'function' ? resolveFn : () => {}
rejectFn = typeof rejectFn === 'function' ? rejectFn : () => {}
if(this.status === YPromise.PEDDING || this.status === YPromise.FULFILLED){
this.fulfilledCallbacks.push(resolveFn)
}else {
this.rejectedCallbacks.push(rejectFn)
}
return this
}
catch(rejectFn){
rejectFn = typeof rejectFn === 'function' ? rejectFn : () => {}
if(this.status === YPromise.PEDDING || this.status === YPromise.REJECTED){
this.rejectedCallbacks.push(rejectFn)
}
return this
}
}
new YPromise((resolve,reject) => {
setTimeout(() => {
resolve('then成功')
},2000)
})
.then(res => {
console.log('then1',res);
return 1111
})
.catch(err => {
console.log('err');
}).then(res => {
console.log(res);
})