实现一个简易的promise

950 阅读5分钟

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件更合理和更强大。想要实现一个promise,则必须要知道它的特点以及实现原理。

Promise对象有以下两个特点:

  1. 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

Promise实现原理:

  • 创建一个promise对象(该promise下面称作promise1),其状态为padding(进行中),需手动调用resolve或reject方法才会切换状态,状态切换后,会执行相应的fulfilled和rejected(这两个回调存储在promise的deferred数组)。
  • 如果回调函数返回的是一个promise对象,则后面的回调函数会存储在返回的promise对象的deferred;如果返回的不是promise,会先判断promise1的状态是否为fulfilled,是,则后面的回调函数存储在promise1的deferred,并且立即执行。不是,则将promise1中deferred数组的promise的状态变为fulfilled,继续执行后面的回调。
  • promise1调用then方法,then接受两个参数fulfilled和rejected,并且创建一个promise,然后将fulfilled、rejected、promise存进一个对象里,在将这个对象推入promise1的deferred数组,返回新创建的promise。

懂了实现原理,我们知道实现一个简易的promise,需要有status(状态)、deferred、value(执行fulfilled和rejected回调时传入的参数)三个属性以及then、resolve、reject、done(执行deferred)这四个方法。

resolve和reject的实现:

	
    /**
    * 推入microtask( 保证其回调是异步执行)。
    * resolve会接受一个value,value会填充promise的value属性。
    * 将promise状态变为fulfilled并执行done方法。
    */
    resolve(value) {
        this.pushMicroTask(() => {
            if (this.status !== 'pendding') return
            this.status = 'fulfilled'
            this.value = value
            this.done()
        });
    }

	// 与resolve一样,只是状态变为rejected
    reject(value) {
        this.pushMicroTask(() => {
            if (this.status !== 'pendding') return
            this.status = 'rejected'
            this.value = value
            this.done()
        });
    }

then的实现

	/**
    * then方法接收onFulfilled、onRejected两个参数
    * 创建新的promise,将onFulfilled、onRejected、新的promise推到deferred
    * 返回新创建的promise
    */
	then(onFulfilled, onRejected) {
        const promise = new CreatPromise()
        const item = {
            onFulfilled,
            onRejected,
            promise
        }
        this.deferred.push(item)
        // promise状态不为padding,则立即执行回调
        if (this.status === 'fulfilled' || this.status === 'rejected') {
        	this.pushMicroTask(this.done.bind(this))
        }
        return promise
    }

done的实现

	done() {
        if (this.status === 'pendding' || this.deferred.length === 0) return
        const _deferred = this.deferred
        // 清空deferred
        this.deferred = []

        for (let i of _deferred) {
            let { success, fail, promise } = i
            let _promise
            /**
             * 执行回调,如果回调函数有报错,则promise状态变为rejected,return,继续处理后面的deferred
             */
            if (this.status === 'fulfilled' && success) {
                try {
                    _promise = success(this.value)
                } catch(err) {
                    promise.reject(err)
                    return
                }
            } else if (this.status === 'rejected' && fail) {
                try {
                    _promise = fail(this.value)
                } catch(err) {
                    promise.reject(err)
                    return
                }
            }

            /**
             * 如果回调函数返回值是promise实例,则后面的deferred由返回的promise实例来处理
             * 返回值不为promise实例分两种情况
             * 1.this状态为rejected且有fail函数,则promise状态变为fulfilled.后面的deferred交由promise处理
             * 2.this状态为fulfilled或rejected,则后面的deferred还是交由当前promise处理
             */
            if (typeof _promise === 'object' && _promise instanceof CreatPromise) {
                _promise.deferred = promise.deferred
            } else if (this.status === 'rejected' && fail) {
                promise.resolve(_promise)
            } else if (this.status === 'fulfilled' || this.status === 'rejected') {
                this.deferred = this.deferred.concat(promise.deferred)
                this.value = _promise || this.value
            }
        }
        // 如果deferred不为空,继续执行
        if (this.deferred.length > 0) this.pushMicroTask(this.done.bind(this))
    }

完整代码

class CreatPromise {
    constructor(callback) {
        // 状态初始化
        this.status = 'pendding'
        this.value = undefined
        this.deferred = []
        // 调用callback,resolve和reject方法作为参数传入
        callback && callback(this.resolve.bind(this), this.reject.bind(this))
    }

    // 模拟promise微任务(可以用MutationObserver实现,这里展示就没用了)
    pushMicroTask (fn) {
        setTimeout(() => {
            fn()
        }, 0);
    }

    resolve(value) {
        this.pushMicroTask(() => {
            if (this.status !== 'pendding') return
            this.status = 'fulfilled'
            this.value = value
            this.done()
        });
    }

    reject(value) {
        this.pushMicroTask(() => {
            if (this.status !== 'pendding') return
            this.status = 'rejected'
            this.value = value
            this.done()
        });
    }

    then(success, fail) {
        const promise = new CreatPromise()
        // 回调信息
        const item = {
            success,
            fail,
            promise
        }
        this.deferred.push(item)
        // 当前promise状态已完成,则立即执行回调
        if (this.status === 'fulfilled' || this.status === 'rejected') this.pushMicroTask(this.done.bind(this))
        return promise
    }

    done() {
        if (this.status === 'pendding' || this.deferred.length === 0) return
        const _deferred = this.deferred
        this.deferred = []
        for (let i of _deferred) {
            let { success, fail, promise } = i
            let _promise
            /**
             * 执行回调,如果回调函数有报错,则promise状态变为rejected,继续处理后面的deferred
             */
            if (this.status === 'fulfilled' && success) {
                try {
                    _promise = success(this.value)
                } catch(err) {
                    promise.reject(err)
                    return
                }
            } else if (this.status === 'rejected' && fail) {
                try {
                    _promise = fail(this.value)
                } catch(err) {
                    promise.reject(err)
                    return
                }
            }

            /**
             * 如果回调函数返回值是promise实例,则后面的回调信息存于返回的promise实例
             * 返回值不为promise实例分两种情况
             * 1:当前promise(this)状态为rejected且有fail函数,则promise状态变为fulfilled.后面的deferred交由promise处理
             * 2.当前primise(this)状态为fulfilled或rejected,则后面的deferred还是交由当前promise处理
             */
            if (typeof _promise === 'object' && _promise instanceof CreatPromise) {
                _promise.deferred = promise.deferred
            } else if (this.status === 'rejected' && fail) {
                promise.resolve(_promise)
            } else if (this.status === 'fulfilled' || this.status === 'rejected') {
                this.deferred = this.deferred.concat(promise.deferred)
                this.value = _promise || this.value
            }
        }
        // 如果deferred不为空,继续执行
        if (this.deferred.length > 0) this.pushMicroTask(this.done.bind(this))
    }

    catch(callback) {
        return this.then(null, callback)
    }

    finally(callback) {
        return this.then(callback, callback)
    }
}
CreatPromise.resolve = function(value) {
    // 如果参数是promise实例,则原封不动返回该实例
    if (value instanceof CreatPromise) return value
    // 如果参数是个thenable对象,则将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。
    if (typeof value === 'object' || typeof value === 'function') {
        const then = value.then
        if (typeof then === 'function') {
            return new CreatPromise(then.bind(value))
        }
    }
    return new CreatPromise((resolve) => resolve(value))
}

CreatPromise.reject = function(error) {
    // reject与resolve不同,会原封不动地作为reject的理由,变成后续方法的参数
    return new CreatPromise((resolve, reject) => reject(error))
}

参考资料

源码地址