开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情
then 方法基础功能实现
上一节我们简单实现了 resolve和reject 对结果的处理,但它的结果是直接输出的,我们希望它能够和们熟悉的用法一样,通过then方法来接受处理结果的回调,现在我们来一起实现一个简单的 then 方法
class MyPromise {
// ...
then(onFulfilled, onRejected) {
if (this.state === MyPromise.fulfilled) {
onFulfilled(this.result)
}
if (this.state === MyPromise.rejected) {
onRejected(this.error)
}
}
}
new MyPromise((resolve, reject) => {
resolve(1)
reject(2)
}).then(res => {
console.log(res);
}, error => {
console.log(error)
})
这里,我们通过 onFulfilled,onRejected 接收我们 then 里的回调函数,通过判断 state 状态来决定走哪个分支,这样一个简单的 then 方法就完成了,但它是一个同步的方法,大家知道 then 最大的作用是异步的处理结果,那我们接下来就对 then 做异步的处理
then 方法异步实现
当传进 MyPromise 的回调函数是一个异步方法的时候,我们就无法保证调用 then 时能够拿到我们想要的结果(异步事件还未处理完),那这个时候 Promise 的状体仍旧处于 Pending 状态,那我们这里可以采用发布订阅者模式,在调用 then 方法过程中,如果状态是 pending 的,先把要执行的函数记录下来,后续状态改变时在把记录的方法执行就可以了
在实现代码之前先简单介绍下发布订阅者模式的实现
发布订阅者的实现思路
- 维护一个缓存列表(事件调度中心)
- 订阅者把函数 fn 添加到缓存列表中(订阅者注册事件到调度中心)
- 发布者在事件发生时通知调度中心(发布者发布事件到调度中心,调度中心处理代码)
按照上述思路我们简单梳理下逻辑
- 事件调度中心
这个场景下,我们需要记录的事件就是 resolve与reject 事件,他们两个是相互独立的,那我们就定义两个数组onResolveCallbacks 和 onRejectCallbacks去作为我们的事件调度中心
// 事件调度中心
this.onResolveCallbacks = []
this.onRejectCallbacks = []
- 订阅者
then 方法则作为订阅者,当执行时如果状态还为 pending 时,把回调方法添加到数组中(事件调度中心)
// 等待状态时暂存回调方法(这里的方法注意用箭头函数包裹起来)
if (this.state === MyPromise.pending) {
this.onResolveCallbacks.push(() => {
onFulfilled(this.result)
})
this.onRejectCallbacks.push(() => {
onRejected(this.error)
})
}
- 发布者
最后当resolve或者reject执行时,作为发布者把事件调度中心注册的事件进行执行
const resolve = (res) => {
if (this.state === MyPromise.pending) {
// ...
// 状态改变发布消息时执行对应调度中心的方法
this.onResolveCallbacks.forEach(callBack => callBack())
}
}
这样,一个简单的订阅发布者模式就完成了,完整代码
class MyPromise {
static pending = 'pending'
static fulfilled = 'fulfilled'
static rejected = 'rejected'
constructor (callBack) {
this.state = MyPromise.pending
this.result = null
this.error = null
this.onResolveCallbacks = []
this.onRejectCallbacks = []
const resolve = (res) => {
if (this.state === MyPromise.pending) {
console.log(this.state + ' => ' + MyPromise.fulfilled)
this.state = MyPromise.fulfilled
this.result = res
this.onResolveCallbacks.forEach(callBack => callBack())
}
}
const reject = (error) => {
if (this.state === MyPromise.pending) {
console.log(this.state + ' => ' + MyPromise.rejected)
this.state = MyPromise.rejected
this.error = error
this.onRejectCallbacks.forEach(callBack => callBack())
}
}
callBack(resolve, reject)
// console.log('result:' + this.result)
// console.log('error:' + this.error)
}
then(onFulfilled, onRejected) {
// Both onFulfilled and onRejected are function
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
onRejected = typeof onRejected === 'function' ? onRejected : (err) => { throw err }
if (this.state === MyPromise.fulfilled) {
onFulfilled(this.result)
}
if (this.state === MyPromise.rejected) {
onRejected(this.error)
}
// 等待状态时暂存回调方法
if (this.state === MyPromise.pending) {
this.onResolveCallbacks.push(() => {
onFulfilled(this.result)
})
this.onRejectCallbacks.push(() => {
onRejected(this.error)
})
}
}
}
我们来试一下执行一下异步方法
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
}).then(res => {
console.log(res);
}, error => {
console.log(error)
})
顺利打印出来没有问题了
好了,本篇已经带大家实现了promise中then的基础功能,但是还不够,我们知道,原生 Promise 的 then 方法是可以链式调用的,也就是可以一直 .then().then()... 下去,下一节我会跟大家一起实现 promise 的 then 的链式调用,敬请关注!