编辑代码

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECT = 'reject'

class MyPromise {
    constructor(exectur) {
        this.status = PENDING // 当前状态
        this.value = '' // 成功值
        this.reason = '' // 失败值
        this.onFulfilledCb = [] // 成功回调
        this.onRejectedCb = [] // 失败回调
        try {
            exectur(this.resolve(), this.reject())
        } catch (err) {
            this.reject(err)
        }
    }
    resolve = (value) => {
        if (this.status === PENDING) {
            this.status === FULFILLED
            this.value = value
            this.onFulfilledCb.forEach(fn => fn())
        }
    }
    reject = (reason) => {
        if (this.status === PENDING) {
            this.status === REJECT
            this.reason = reason
            this.onRejectedCb.forEach(fn => fn())
        }
    }
    then = (onFulfilled, onRejected) => {
        // 保证then的回调函数是function
        onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : value => value
        onRejected = typeof onRejected == 'function' ? onRejected : (err) => { throw err };
        let promise2
        if (this.status === PENDING) {
            // 返回一个新的promise
            promise2 = new MyPromise((resolve, reject) => {
                // 当成功或失败执行时,有异常那么返回的promise应该处于失败态
                // 用try/catch来防止返回异常的情况
                // 加上setTimeout实现异步调用
                this.onFulfilledCb.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value)
                            // x也可能是别人写的promise,写一个函数统一去处理
                            resolvePromise(this, x, resolve, reject)
                        } catch (err) {
                            reject(err)
                        }

                    })
                })
                this.onRejectedCb.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reason)
                            resolvePromise(this, x, resolve, reject)
                        } catch (err) {
                            reject(err)
                        }

                    })
                })
            })
        }
        if (this.status === FULFILLED) {
            promise2 = new MyPromise((resolve, reject) => {
                setTimeout(() => {
                    try {
                        let x = onFulfilled(this.value)
                        resolvePromise(this, x, resolve, reject)
                    } catch (err) {
                        reject(err)
                    }
                })

            })

        }
        if (this.status === REJECT) {
            promise2 = new MyPromise((resolve, reject) => {
                setTimeout(() => {
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(this, x, resolve, reject)
                    } catch (err) {
                        reject(err)
                    }
                })
            })
        }
        return promise2
    }

    catch = callback => {
        return this.then(null, callback)
    }
    // 只要所有参数实例变成fulfilled状态,包装实例才会变成fulfilled状态;
    // 只要一个参数实例都变成rejected状态,包装实例就会变成rejected状态
    all = list => {
        return new MyPromise((resolve, reject) => {
            let count = 0
            let result = []
            let len = list.length
            if (len === 0) {
                return resolve(result)
            }
            list.forEach((item, index) => {
                MyPromise.resolve(item).then((value) => {
                    count++
                    result.push(value)
                    if (count === len) {
                        return resolve(result)
                    }
                }, reason => {
                    reject(reason)
                })
            })
        })
    }
    // 只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;
    // 如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态
    any = list => {
        return new MyPromise((resolve, reject) => {
            let count = 0
            let result = []
            let len = list.length
            if (len === 0) return resolve(result)
            list.forEach((item, index) => {
                MyPromise.resolve(item).then(value => {
                    resolve(value)
                }, reason => {
                    count++
                    result.push(reason)
                    if (count === len) {
                        reject(result)
                    }
                })
            })
        })
    }
    race = list => {
        return new MyPromise((resolve, reject) => {
            let len = list.length
            list.forEach(item => {
                MyPromise.resolve(item).then(value => {
                    resolve(value)
                }, reason => {
                    reject(reason)
                })
            })
        })
    }

    finally = fn => {
        return this.then(value => {
            return MyPromise.resolve(fn()).then(() => {
                return value
            })
        }, reason => {
            return MyPromise.resolve(fn()).then(() => {
                throw reason
            })
        })
    }
}

function resolvePromise(promise, x, resolve, rejcet) {
    // 不能返回自己 循环引用
    if (promise === x) {
        return rejcet(new TypeError('cycle...'))
    }
    let called = false   // 表示是否调用成功or失败
    // x返回的可能是对象和函数也可能是一个普通的值
    if (['null', 'function'].includes(typeof x) && typeof x !== null) {
        try {
            let then = x.then
            // 处理then不是函数的情况,如{then: 1},就直接返回成功
            if (typeof then === 'funciton') {
                then.call(x, y => {
                    if (called) return
                    called = true
                    // y可能还是个promise,所以递归继续解析直到返回一个普通值
                    resolvePromise(promise, y, resolve, rejcet)
                }, error => {
                    if (called) return
                    called = true
                    reject(error)
                })
            } else {
                resolve(x)
            }
        } catch (err) {
            if (called) return
            called = true
            reject(err)
        }
    } else {
        resolve(x)
    }
}