手写Promise系列(二)

228 阅读2分钟

开篇

这是手写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,有问题欢迎在评论区指出。