Promise实现

Promise实现


const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MPromise {

    FULFILLED_CALLBACK_LIST = []
    REJECTED_CALLBACK_LIST = []

    // 私有变量,存储真正的status
    _status = PENDING

    constructor(fn) {
        this.status = PENDING
        // fulfilled 值
        this.value = null
        // rejected 值
        this.reason = null

        try {
            fn(this.resolve.bind(this), this.reject.bind(this))
        } catch (e) {
            this.reject(e)
        }
    }

    get status() {
        return this._status
    }

    set status(newStatus) {
        this._status = newStatus
        switch (newStatus) {
            case FULFILLED: {
                this.FULFILLED_CALLBACK_LIST.forEach(callback => {
                    callback(this.value)
                });
                break
            }
            case REJECTED: {
                this.REJECTED_CALLBACK_LIST.forEach(callback => {
                    callback(this.reason)
                });
                break
            }
        }
    }

    resolve(value) {
        if (this.status === PENDING) {
            this.value = value
            this.status = FULFILLED
        }
    }

    reject(reason) {
        if (this.status === PENDING) {
            this.reason = reason
            this.status = REJECTED
        }
    }

    // param:Promise 结束后调用的 Function。
    // return: 一个设置了 finally 回调函数的 Promise 对象。这个Promise对象可以继续finally之前then的结果
    finally(callback) {
        return this.then(value => {
            return MPromise.resolve(callback()).then(() => value)
        }, err => {
            return MPromise.resolve(callback()).then(() => { throw err })
        })
    }

    then(onFulfilled, onRejected) {
        const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : value => value
        const realOnRejected = this.isFunction(onRejected) ? onRejected : reason => { throw reason }

        const promise2 = new MPromise((resolve, reject) => {

            const fulfilledMicrotask = () => {
                queueMicrotask(() => {
                    try {
                        // 实现链式调用的关键
                        const x = realOnFulfilled(this.value)
                        this.resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })
            }
            const rejectedMicrotask = () => {
                queueMicrotask(() => {
                    try {
                        // 实现链式调用的关键
                        const x = realOnRejected(this.reason)
                        this.resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })
            }
            switch (this.status) {
                case FULFILLED: {
                    fulfilledMicrotask()
                    break
                }
                case REJECTED: {
                    rejectedMicrotask()
                    break
                }
                case PENDING: {
                    this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)
                    this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask)
                }
            }
        })
        return promise2
    }

    resolvePromise(promise2, x, resolve, reject) {
        // 简单版本: resolve(x)

        // 以下为复杂版本:
        if (promise2 === x) {
            return reject(new TypeError('param and return are same'))
        }

        if (x instanceof MPromise) {
            queueMicrotask(() => {
                x.then(y => {
                    this.resolvePromise(promise2, y, resolve, reject)
                }, reject)
            })


        } else if (x && (typeof x === 'object' || this.isFunction(x))) {

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

            // 如果then是函数
            if (this.isFunction(then)) {
                let called = false
                try {
                    then.call(x, y => {
                        if (called) return
                        called = true
                        this.resolvePromise(promise2, y, resolve, reject)
                    }, r => {
                        if (called) return
                        called = true
                        reject(r)
                    })

                } catch (e) {
                    if (called) {
                        return
                    }
                    reject(e)
                }

            } else {
                resolve(x)
            }

        } else {
            resolve(x)
        }
    }

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

    isFunction(param) {
        return typeof param === 'function'
    }


    // Promise.resolve() 静态方法将给定的值转换为一个 Promise。如果该值本身就是一个 Promise,那么该 Promise 将被返回;
    static resolve(value) {
        if (value instanceof MPromise) {
            return value
        }
        return new MPromise(resolve => resolve(value))
    }

    // Promise.reject() 静态方法返回一个已拒绝(rejected)的 Promise 对象,拒绝原因为给定的参数。
    static reject(reason) {
        return new MPromise((resolve, reject) => {
            reject(reason)
        })
    }

    // Promise.race(promiseList) 返回一个 Promise。这个返回的 promise 会随着第一个 promise 的敲定而敲定。
    static race(promiseList) {
        return new MPromise((resolve, reject) => {
            const length = promiseList.length

            if (length === 0) {
                return resolve()
            } else {
                for (let i = 0; i < length; i++) {
                    MPromise.resolve(promiseList[i])
                        .then(v => resolve(v))
                        .catch(r => reject(r))
                }
            }

        })
    }

    // Promise.all(promiseList) 返回一个 Promise。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。
    static all(promiseList) {
        return new MPromise((resolve, reject) => {
            const length = promiseList.length
            if (length === 0) {
                return MPromise.resolve([])
            }
            let count = 0,
                result = new Array(length)
            for (let i = 0; i < length; j++) {
                MPromise.resolve(promiseList[i])
                    .then((val) => {
                        count++;
                        result[i] = val
                        if (count === length) {
                            return resolve(result)
                        }
                    })
                    .catch(r => reject(r))
            }
        })
    }

    // Promise.any(promiseList) 返回一个 Promise。当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝。
    static any(promiseList) {
        return new MPromise((resolve, reject) => {
            const length = promiseList.len
            if (length === 0) {
                return MPromise.resolve([])
            }
            let errcount = 0
            const errResult = new Array(length)
            for (let i = 0; i < length; i++) {
                MPromise.resolve(promiseList[i])
                    .then(v => resolve(v))
                    .catch(r => {
                        errResult[i] = reject(i)
                        errcount++
                        if (errcount.length === length) {
                            reject(errResult)
                        }
                    })
            }
        })
    }

    // Promise.allSettled(promiseList) 返回一个单独的 Promise。当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组。
    // PromiseState 一直为 fulfilled
    static allSettled(promiseList) {
        return MPromise((resolve) => {
            const length = promiseList.len
            if (length === 0) {
                return MPromise.resolve([])
            }
            const resultArr = new Array[length]
            let count = 0
            for (let i = 0; i < length; i++) {
                MPromise.resolve(promiseList[i])
                    .then(value => {
                        resultArr[i] = {
                            value,
                            status: FULFILLED
                        }
                        count++
                        if (count === length) {
                            resolve(resultArr)
                        }
                    })
                    .catch(reason => {
                        resultArr[i] = {
                            reason,
                            status: REJECTED
                        }
                        count++
                        if (count === length) {
                            resolve(resultArr)
                        }
                    })
            }
        })
    }

}

module.exports  = MPromise


const test = new MPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(111)
        // reject(1)
    }, 1000)
}).then(v => console.log(`[then] value=${v}`)).catch(r => console.log(`[catch] reason = ${r}`))

// console.log(test)