你会不会深度还原Promise实现原理,更新中。。

236 阅读4分钟
/**
 * 2. 定义3种状态类型
 */
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

// 1.使用类而替代构造函数
class myPromise {
    // 6.4 当promise状态变成fulfilled和rejected后,需要执行对应状态的回调
    // 但此前status仍然是pending,有必要缓存各状态变化后需要执行的回调
    // 6.4.1 初始化成功的所有回调
    FULFILLED_CALLBACK_LIST = []
    // 6.4.2 初始化失败的所有回调
    REJECTED_CALLBACK_LIST = []

    // 6.5.1 监听真实的status,初始化待劫持变量:
    _status = PENDING

    // 5.对实例化promise时入参的处理
    constructor(
        fn // 5.1 promise入参是一个函数,const promise = new Promise((resolve, reject) => { axios.get() })
    ) {
        // 3. 初始化promise状态,成功值,失败值
        this.status = PENDING
        this.value = null
        this.reason = null
        // 5.2 在初始化promise的时候
        try {
            // 5.2.1 该函数接收resolve和reject两个参数,并立即执行
            fn(this.resolve.bind(this), this.reject.bind(this))
            // 由于resolve方法未使用箭头函数,所以绑定this至当前执行环境确保this执行正确
        } catch (error) {
            // 5.2.2 有任何报错都要通过reject抛出去
            this.reject(error)
        }
    }

    // 6.5 使用setter, getter, 当status放生变化时,执行对应回调,而不是在resolve, reject函数中直接调用
    // 6.5.2 getter方法可以获取到最新的_status
    get status() {
        return this._status 
    }
    // 6.5.3 setter方法会监听status值的变化并记录赋给_status
    set status(new_status) {
        this._status = new_status
        switch (new_status) {
            case FULFILLED: {
                this.FULFILLED_CALLBACK_LIST.forEach(cb => cb(this.value))
                break;
            }
            case REJECTED: {
                this.REJECTED_CALLBACK_LIST.forEach(cb => cb(this.reason))
                break;
            }
        }
    }

    // 4. 根据规范,设定更改status的方法resolve和reject
    /**
     * 4.1 pending -> resolve(value) -> fulfilled
     * @param {promise状态成功时的值} value 
     */
    resolve(value) {
        if (this.status === PENDING) {
            this.value = value // 写在状态更新前,便于状态改变后回调中使用
            this.status = FULFILLED
            // 如果在这里调用FULFILLED_CALLBACK_LIST里所有回调,不符合语义,在这个执行栈中有同步执行的顺序
            // 而我们在面向过程写,不了解执行顺序的人容易翻车
        }
    }
    /**
     * 4.2 pending -> reject(reason) -> rejected
     * @param {promise状态失败时的值}} reason 
     */
    reject(reason) {
        if (this.status === PENDING) {
            this.reason = reason
            this.status = REJECTED
            // 调用REJECTED_CALLBACK_LIST里所有回调,和resolve同理 
        }
    }

    /**
     * 6. then方法
     * @param {状态成功回调} onFulfilled: any
     * @param {状态失败回调} onRejected: any
     */
    then(onFulfilled, onRejected) {
        // 6.1 检查then方法的参数是否是函数,如果不是函数,就忽略
        const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : value => value
        const rejectedFn = this.isFunction(onRejected) ? onRejected :  reason => {
            throw reason
        }

        /**
         * 7. then的返回值
         * const promise2 = new myPromise((resovle, reject) => {})
         * 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,
         * 则 promise2 必须拒绝执行,并返回拒因 e。
         * (这样的话, 我们就需要手动catch代码,遇到报错就reject)
         */
        const fulFulledFnWithCatch = (resolve, reject, newPromise) => {
            // onFulfilled和onRejected都是微任务
            queueMicrotask(() => {
                try {
                    // fulFilledFn(this.value)
                    // 7.3 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
                    // resolve(this.value)
                    // 7.5.1
                    if (!this.isFunction(onFulfilled)) {
                        resolve(this.value)
                    } else {
                        const x = fulFilledFn(this.value)
                        this.resolvePromise(newPromise, x, resolve, reject)
                    }
                } catch (error) {
                    reject(error) // 7.1 如果 onFulfilled 或者 onRejected 抛出一个异常 e 
                }
            })
        }

        const rejectedFnWithCatch = (resolve, reject, newPromise) => {
            queueMicrotask(() => {
                try {
                    // 7.4 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因。
                    // rejectedFn(this.reason)
                    // 7.4 需要注意的是,如果promise1的onRejected执行成功了,promise2应该被resolve
                    // if (this.isFunction(onRejected)) {
                        // resolve()
                    // }
                    // 7.5.2
                    if (!this.isFunction(onRejected)) {
                        reject(this.reason)
                    } else {
                        const x = rejectedFn(this.reason)
                        this.resolvePromise(newPromise, x, resolve, reject)
                    }
                } catch (error) {
                    reject(error) // 7.1 如果 onFulfilled 或者 onRejected 抛出一个异常 e 
                }
            })
        }

        // 6.2 根据promise的状态调用不同的函数
        switch (this.status) {
            // 6.2.1 如果成功,将this.value交给onFulfilled执行出去
            case FULFILLED: {
                // fulFilledFn(this.value)
                // fulFulledFnWithCatch(this.value)
                // break;
                // return new myPromise(fulFulledFnWithCatch) // 7.2返回值需是一个promise
                const newPromise = new myPromise((resolve, reject) => {
                    fulFulledFnWithCatch(resolve, reject, newPromise)
                })
                return newPromise
            }// 6.2.2 如果失败,将this.reason交给onRejected抛出
            case REJECTED: {
                // rejectedFn(this.reason)
                // rejectedFnWithCatch(this.reason)
                // break;
                // return new myPromise(rejectedFnWithCatch) // 7.2 返回值需是一个promise
                const newPromise = new myPromise((resolve, reject) => {
                    rejectedFnWithCatch(resolve, reject, newPromise)
                })
                return newPromise 
            }// 6.4 拿到所有的待执行回调
            case PENDING:{
                // this.FULFILLED_CALLBACK_LIST.push(fulFilledFn)
                // this.REJECTED_CALLBACK_LIST.push(rejectedFn)
                // break;
                // return new myPromise((resolve, reject) => {  // 7.2 返回值需是一个promise
                //     this.FULFILLED_CALLBACK_LIST.push(() => { fulFulledFnWithCatch(resolve, reject) })
                //     this.REJECTED_CALLBACK_LIST.push(() => { rejectedFnWithCatch(resolve, reject) })
                // })
                const newPromise = new myPromise((resolve, reject) => {  // 7.2 返回值需是一个promise
                    this.FULFILLED_CALLBACK_LIST.push(() => { fulFulledFnWithCatch(resolve, reject, newPromise) })
                    this.REJECTED_CALLBACK_LIST.push(() => { rejectedFnWithCatch(resolve, reject, newPromise) })
                })
                return newPromise
                /**
                 * const promise = new Promise((resolve, reject) => {
                 *     6.3 这里可能是同步,也可能是异步,所以状态的改变也可能是同步也可能是异步
                 *     resolve('同步')
                 *     setTimeout(() => {
                 *         reject('异步')
                 *     }, 1000)
                 * }).then((onFulfilled, onRejected) => {
                 *    6.4.3 执行then时,如果状态还是pending状态,将成功,失败的回调各自存入
                 *    相应数组FULFILLED_CALLBACK_LIST,REJECTED_CALLBACK_LIST,
                 *    当status发生变化时,执行变化后状态下的所有回调
                 * })
                 */
            }
        }
    }

    /**
     * 
     * @param {catch参数} onRejected 
     * @returns 
     */
    catch(onRejected) {
        return this.then(null, onRejected)
    }
    /**
     * 7.5 如果 onFulfilled 或者 onRejected 返回一个值 x 且没报错,则运行resolvePromise方法
     * @param {新函数的promise} newPromise 
     * @param {上一个promise的值} x 
     * @param {成功回调} resolve 
     * @param {失败回调} reject 
     */
    resolvePromise(newPromise, x, resolve, reject) {
        if (newPromise === x) {
            return reject(new TypeError('max call stack exceeded'))
        }
        if (x instanceof myPromise) {
            x.then(
                (y) => {
                    this.resolvePromise(newPromise, y, resolve, reject)
                },
                reject
            )
        } else if (
            // Object.prototype.toString.call(x) === '[object, Object]'
            typeof x === 'object' ||  this.isFunction(x)
        ) {
            if (x === null) {
                return resolve(x)
            }

            let then = null
            try {
                then = x.then
            } catch (error) {
                return reject(error)
            }

            if (this.isFunction(then)) {
                // onFulflled, onRejected只能调用一次
                let called = false
                try {
                    x.then.call(
                        x,
                        (y) => {
                            if (called) return
                            called = true
                            this.resolvePromise(newPromise, y, resolve, reject)
                        },
                        (r) => {
                            if (called) return
                            called = true
                            reject(r)
                        }
                    )
                } catch (error) {
                    if (called) {
                        return
                    }
                    reject(error)
                }
            } else {
                resolve(x)
            }

        } else {
            resolve(x)
        }
    }
    /**
     * 校验是否是函数
     * @param {待校验的值} param 
     * @returns Boolean
     */
    isFunction(param) {
        return typeof param === 'function'
    }
}