简易实现Promise的几个功能包含异步处理、回调处理、链式调用、异常捕获等基础功能。
原生Promise功能
// 后面手写需要实现的功能
let a = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(11)
// reject(22)
}, 200)
})
a.then((res) => {
console.log(res);
return '新的'
}).then((res) => {
console.log(res);
return Promise.reject('我错了')
}).catch((res) => {
console.log('error:', res);
})
// 以上代码输出内容:
11
新的
error: 我错了
代码解析:给Promise的构造器传一个参数,这个参数是一个立即执行的回调函数,该回调函数就是Promise实现异步的核心。
手写实现上述Promise功能
定义一个包含构造函数的myPromise类,其中包含state和result两个字段,构造函数接收并执行一个函数参数fun,执行fun函数的时候将本身的resolve和reject处理函数传过去。resolve和reject需要使用箭头函数,不然会存在this指向问题。
state: 包含三种状态:pendding、success(最终态)、fail(最终态),分别代表异步执行等待中、异步执行成功、异步执行失败的状态。
result: 代表函数执行结束时传递的值。
class myPromise {
state = 'pendding'
result = null
constructor(fun) {
this.state = 'pendding'
this.result = null
fun(this.resolve, this.reject)
}
resolve = (data) => {
}
reject = (data) => {
}
}
完善resolve和reject函数,将函数状态和函数结果参数进行赋值,由于Promise中状态不可逆,最终只能由pending变成完成态(success或fail),所以增加状态判断。
class myPromise {
state = 'pendding'
result = null
constructor(fun) {
this.state = 'pendding'
this.result = null
fun(this.resolve, this.reject)
}
resolve = (data) => {
if (this.state === 'pendding') {
this.state = 'success'
this.result = data
}
}
reject = (data) => {
if (this.state === 'pendding') {
this.state = 'fail'
this.result = data
}
}
}
增加成功回调函数then和错误处理函数catch,用于处理异步操作。实现异步处理,还需增加两个参数successCallback,failCallback,由于在实例中调用时是同步操作,所以在状态未变成最终态时先使用参数将回调存储下来,等状态变化后再执行相应的回调函数。
class myPromise {
state = 'pendding'
result = null
successCallback = null
failCallback = null
constructor(fun) {
this.state = 'pendding'
this.result = null
fun(this.resolve, this.reject)
}
resolve = (data) => {
if (this.state === 'pendding') {
this.state = 'success'
this.result = data
this.successCallback && this.successCallback(this.result)
}
}
reject = (data) => {
if (this.state === 'pendding') {
this.state = 'fail'
this.result = data
this.failCallback && this.failCallback(this.result)
}
}
then(callBack) {
if (this.state === 'success') {
callBack(this.result)
} else {
this.successCallback = callBack
}
return this
}
catch(callBack) {
if (this.state === 'fail') {
callBack(this.result)
} else {
this.failCallback = callBack
}
return this
}
}
为了实现then函数的链式调用,需要执行then后将this实例返回,同时将successCallback参数变成数组,在调用的时候循环调用。而每一次then函数的返回值将作为下一次执行的时候的参数,所以得更新result参数,此时需要根据then函数的返回值判断一下是否是Promise本身,并且需要看state是否变为fail,如果状态在中间变为fail,则直接执行catch回调。并且后面的then函数不会再执行。同时定义两个静态函数resolve和reject,返回实例化对象,此对象只处理同步操作改变state状态。在successCallback中判断返回参数是否是Promise实例并判断状态。以下是完成代码
class myPromise {
state = 'pendding'
result = null
successCallback = []
failCallback = null
constructor(fun) {
this.state = 'pendding'
this.result = null
fun(this.resolve, this.reject)
}
resolve = (data) => {
if (this.state === 'pendding') {
this.state = 'success'
this.result = data
if (this.successCallback && this.successCallback.length) {
this.successCallback.forEach(el => {
if (this.state === 'success') {
let res = el(this.result)
if (res instanceof myPromise) {
if (res.state === 'success') {
this.result = res.result
this.state = 'success'
} else if (res.state === 'fail') {
this.state = 'pendding'
this.reject(res.result)
}
} else if (res) {
this.result = res
}
}
})
}
}
}
reject = (data) => {
if (this.state === 'pendding') {
this.state = 'fail'
this.result = data
this.failCallback && this.failCallback(data)
}
}
then(callBack) {
if (this.state === 'success') {
callBack(this.result)
} else {
this.successCallback.push(callBack)
}
return this
}
catch(callBack) {
if (this.state === 'fail') {
callBack(this.result)
} else {
this.failCallback = callBack
}
return this
}
static reject = (data) => {
return new myPromise((a, b) => {b(data)})
}
static resolve = (data) => {
return new myPromise((a, b) => {a(data)})
}
}
let b = new myPromise((a, b) => {
setTimeout(() => {
a('aaaaa')
}, 1000)
})
b.then((res) => {
console.log('success:', res);
return '新的'
}).then(res => {
console.log('success1:', res);
return myPromise.reject('错的')
}).then(res => {
console.log('success2:', res); // 这里不会执行,因为在上面的then中状态变为fail
}).catch((res) => {
console.log('error:', res);
})
// 执行结果:
success: aaaaa
success1: 新的
error: 错的