开篇
这是手写Promise系列的第二篇,主要解决的是第一篇遗留的问题---异步处理,没看过的小伙伴可以先看下我的上一篇文章手写Promise系列(一)。
发布订阅
我们都知道Promise的出现最直接要解决的问题就是前端的回调地狱问题,不然意义就大打折扣了,那么我们接下来来实现Promise异步机制,很明显,我们会采用发布订阅的模式来实现异步机制:
const PENDDING = 'PENDDING' // 初始化状态
const RESOLVED = 'RESOLVED' // 完成状态
const REJECTED = 'REJECTED' // 错误状态
// 声明一个Promise类
class Promise {
// 传入executor:包含resolve和reject方法
constructor(executor) {
// 初始化状态
this.status = PENDDING
// 正常时返回值
this.value = undefined
// 错误时返回值
this.reason = undefined
// 成功函数队列
this.resolveCallbacks = []
// 失败函数队列
this.rejectCallbacks = []
// 声明resolve方法
let resolve = (value) => {
// 判断是否是初始状态
// Promise状态是不可逆的
// status一经修改就不可变
if(this.status === PENDDING) {
// 赋值value
this.value = value
// 改变状态为完成状态
this.status = RESOLVED
// 执行成功回调队列
this.resolveCallbacks.forEach(callback => {
callback(this.value)
})
}
}
// 生命reject方法
let reject = (reason) => {
// 判断是否出错
// Promise状态是不可逆的
// status一经修改就不可变
if(this.status === PENDDING) {
// 赋值错误原因reason
this.reason = reason
// 改变状态为错误状态
this.status = REJECTED
// 执行失败回调队列
this.rejectCallbacks.forEach(callback => {
callback(this.reason)
})
}
}
// 执行executor
try {
if(executor) {
// 执行并传入resolve和reject
executor(resolve,reject)
}
}catch(error) {
// 如果有报错,则直接执行reject
reject(error)
}
}
// 注册then方法
then = (resolve,reject) => {
if(this.status === RESOLVED) {
resolve(this.value)
}
if(this.status === REJECTED) {
reject(this.reason)
}
/**
* 添加发布事件
* 如果是异步事件,则分别发布resolve和reject进入对应的事件队列
*/
if(this.status === PENDDING) {
// 推入成功事件队列
this.resolveCallbacks.push(resolve)
// 推入失败事件队列
this.rejectCallbacks.push(reject)
}
}
// 注册catch方法
catch = (failCallback) => {
// catch实际上是执行then方法里的reject回调
// 直接调用then方法
// 正常返回函数直接传入空
// 只传入failCallback
return this.then(null, failCallback)
}
}
我们可以来测试一下以上代码:
const promise = new Primise(function(resolve, reject) {
// 用setTimout模拟一下异步,3秒后执行
setTimeout(() => {
resolve('hello promise')
}, 3000)
})
promise.then((value) => {
// 我们可以看到,3秒后在控制台里执行了打印出来的hello promise
console.log(value)
})
添加了发布订阅模式之后,异步的问题也就完美解决了,这个模式也是比较常用的模式,至此一个基本的Promise就已经完成了。
总结
增加了异步机制的处理之后,Promise的常用功能就已经实现了,但是我们还有很多细节没有处理,没关系接下去,我们会照着官方标准一步步来完善我的Promise,有问题欢迎在评论区指出。