手写Promise,从Promise使用结合PromiseA+规范为参考依据,实现一个满足日常常用的的异步处理Promise版本

66 阅读15分钟

目前前端开发需要使用异步处理,而异步往往离不开Promise,手写Promise理解其原理就必不可少了;以下会实现Promise异步处理、链式调用、错误捕获、并且实现静态方法all、resolve,满足日常开发时常用的一些Promise功能,让理解Promise原理。

参考连接:

目录

一、实现Promise基本功能

二、同一个promise下面then方法是可以被多次调用的

三、实现Promise链式调用

四、实现捕获错误以及catch方法

五、静态方法Promise.all()和Promise.resolve()实现

六、实现finally方法

七、完整代码

一、实现Promise基本功能

日常工作时候最常用的功能是处理异步调用接口,比如处理异步后通过then方法获取到成功或者失败的异步结果,这是日常工作中最常见需要的功能。
  1. 创建一个ajax请求,并调用接口获取接口返回的值
function ajax(url) {
    return new MyPromise(function(resolve, reject) {
        var xhr = new XMLHttpRequest()
        xhr.open('GET', url)
        xhr.responseType = 'json'
        xhr.onload = function(){
            console.log('this====', this)
            if(this.status === 200){
                resolve(this.response)
            }else {
                reject(new Error(this.statusText))
            }
        }
        xhr.send()
    })
}
// 接口地址根据自己情况去修改传入
ajax('/api/users.json').then(res => {
    console.log('res======', res)
}, err => {
    console.log('err=', err)
})
  1. 基本版Promise功能

MyPromise代码如下:

// 使用常量来标示Promise三种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise{
    constructor(executor){
        // 设定初始状态为pending
        this.status = PENDING
        // 存储resoleve和reject回调传递的参数
        this.value = undefined
        this.reason = undefined

        // 存储成功onFulfilled和失败onRejected回调
        this.onFulfilled = null
        this.onRejected = null

        // 需要使用bind方法将this绑定,不然会获取不到当前实例中的值
        executor(this.resolve.bind(this), this.reject.bind(this))

    }
    // resolve方法,改变状态为成功,存储传入的参数
    resolve(value){
        if(!(this.status === PENDING)){
            return
        }
        this.status = FULFILLED
        this.value = value
        // 判断成功回调是否存在,如果存在执行它并传入value参数
        this.onFulfilled && this.onFulfilled(this.value)
    }
    // reject方法,改变状态为失败,存储传入的失败原因参数
    reject(reason){
        if(!(this.status === PENDING)){
            return
        }
        this.status = REJECTED
        this.reason = reason
        // 判断失败回调是否存在,如果存在执行它并传入reason参数
        this.onRejected && this.onRejected(this.reason)
    }

    // then方法,内部就是做判断,如果状态成功调用成功的回调,如果状态失败则调用失败的回调
    then(onFulfilled, onRejected){
        if(this.status === FULFILLED){
            onFulfilled(this.value)
        } else if(this.status === REJECTED){
            onRejected(this.reason)
        } else {
            // 走到这里的原因是:主线程中的代码不会等到异步代码执行完再执行,而是立即执行的,因此异步情况下执行到then后状态还是padding,处在等待过程中。
            // 此时还没有执行resolve和reject,而程序又走到了then并且传入了onFulfilled或onRejected,因此需要将onFulfilled和onRejected存储起来,等待执行到resolve或reject之后再去执行onFulfilled和onRejected
            this.onFulfilled = onFulfilled
            this.onRejected = onRejected
        }
    }
}

export default MyPromise

二、同一个promise下面then方法是可以被多次调用的

1. 案例:

const p1 = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(6666666)
    }, 3000)
})
p1.then(r => {
    setTimeout(() => {
        console.log('r1=',r)
    },1000)
})
p1.then(r => {
    console.log('r2=',r)
})
p1.then(r => {
    console.log('r3=',r)
})

  1. 代码变更
  • 存储成功onFulfilled和失败onRejected回调初始值变为空数组
        // 存储成功onFulfilled和失败onRejected回调
        this.onFulfilled = null
        this.onRejected = null
        // 存储成功onFulfilled和失败onRejected回调
        this.onFulfilled = []
        this.onRejected = []
  • 在then方法中处理异步状态时,将回调由赋值改变为每个回调push到数组中
    then(onFulfilled, onRejected){
        if(this.status === FULFILLED){
            onFulfilled(this.value)
        } else if(this.status === REJECTED){
            onRejected(this.reason)
        } else {
            // 走到这里的原因是:主线程中的代码不会等到异步代码执行完再执行,而是立即执行的,因此异步情况下执行到then后状态还是padding,处在等待过程中。
            // 此时还没有执行resolve和reject,而程序又走到了then并且传入了onFulfilled或onRejected,因此需要将onFulfilled和onRejected存储起来,等待执行到resolve或reject之后再去执行onFulfilled和onRejected
            this.onFulfilled = onFulfilled
            this.onRejected = onRejected
        }
    }
    then(onFulfilled, onRejected){
        if(this.status === FULFILLED){
            onFulfilled(this.value)
        } else if(this.status === REJECTED){
            onRejected(this.reason)
        } else {
            // 走到这里的原因是:主线程中的代码不会等到异步代码执行完再执行,而是立即执行的,因此异步情况下执行到then后状态还是padding,处在等待过程中。
            // 此时还没有执行resolve和reject,而程序又走到了then并且传入了onFulfilled或onRejected,因此需要将onFulfilled和onRejected存储起来,等待执行到resolve或reject之后再去执行onFulfilled和onRejected
            this.onFulfilled.push(onFulfilled)
            this.onRejected.push(onRejected)
        }
  • 执行回调时,变更为每执行一个删除一个
    // resolve方法,改变状态为成功,存储传入的参数
    resolve(value){
        if(!(this.status === PENDING)){
            return
        }
        this.status = FULFILLED
        this.value = value
        // 判断成功回调是否存在,如果存在执行它并传入value参数
        this.onFulfilled && this.onFulfilled(this.value)
    }
    // reject方法,改变状态为失败,存储传入的失败原因参数
    reject(reason){
        if(!(this.status === PENDING)){
            return
        }
        this.status = REJECTED
        this.reason = reason
        // 判断失败回调是否存在,如果存在执行它并传入reason参数
        this.onRejected && this.onRejected(this.reason)
    }
    // resolve方法,改变状态为成功,存储传入的参数
    resolve(value){
        if(!(this.status === PENDING)){
            return
        }
        this.status = FULFILLED
        this.value = value
        // 判断成功回调是否存在,如果存在执行它并传入value参数,每执行一个删除一个
        while(this.onFulfilled.length) this.onFulfilled.shift()(this.value)
    }
    // reject方法,改变状态为失败,存储传入的失败原因参数
    reject(reason){
        if(!(this.status === PENDING)){
            return
        }
        this.status = REJECTED
        this.reason = reason
        // 判断失败回调是否存在,如果存在执行它并传入reason参数,每执行一个删除一个
        while(this.onRejected.length) this.onRejected.shift()(this.reason)
    }
  1. 变更后整体代码
// 使用常量来标示Promise三种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise{
    constructor(executor){
        // 设定初始状态为pending
        this.status = PENDING
        // 存储resoleve和reject回调传递的参数
        this.value = undefined
        this.reason = undefined

        // 存储成功onFulfilled和失败onRejected回调
        this.onFulfilled = []
        this.onRejected = []


        // 需要使用bind方法将this绑定,不然会获取不到当前实例中的值
        executor(this.resolve.bind(this), this.reject.bind(this))

    }
    // resolve方法,改变状态为成功,存储传入的参数
    resolve(value){
        if(!(this.status === PENDING)){
            return
        }
        this.status = FULFILLED
        this.value = value
        // 判断成功回调是否存在,如果存在执行它并传入value参数,每执行一个删除一个
        while(this.onFulfilled.length) this.onFulfilled.shift()(this.value)
    }
    // reject方法,改变状态为失败,存储传入的失败原因参数
    reject(reason){
        if(!(this.status === PENDING)){
            return
        }
        this.status = REJECTED
        this.reason = reason
        // 判断失败回调是否存在,如果存在执行它并传入reason参数,每执行一个删除一个
        while(this.onRejected.length) this.onRejected.shift()(this.reason)
    }

    // then方法,内部就是做判断,如果状态成功调用成功的回调,如果状态失败则调用失败的回调
    then(onFulfilled, onRejected){
        if(this.status === FULFILLED){
            onFulfilled(this.value)
        } else if(this.status === REJECTED){
            onRejected(this.reason)
        } else {
            // 走到这里的原因是:主线程中的代码不会等到异步代码执行完再执行,而是立即执行的,因此异步情况下执行到then后状态还是padding,处在等待过程中。
            // 此时还没有执行resolve和reject,而程序又走到了then并且传入了onFulfilled或onRejected,因此需要将onFulfilled和onRejected存储起来,等待执行到resolve或reject之后再去执行onFulfilled和onRejected
            this.onFulfilled.push(onFulfilled)
            this.onRejected.push(onRejected)
        }
    }
}

export default MyPromise

三、实现Promise链式调用

链式调用写法参考 https://es6.ruanyifeng.com/#docs/promise 中3.Promise.prototype.then() - 要想实现链式调用,每一个then方法需要返回一个promise对象才能进行链式调用 - 链式调用的核心是链式调用回调方法中返回的参数取决于上一个方法的返回值
  1. 需要在then方法里面变更,并添加resolvePromise方法,代码如下:
    resolvePromise(x, resolve, reject){
        /*
        1、判断x的值是普通值还是promise对象
        2、如果是普通值直接调用resolve并传值进去
        3、如果是promise对象,查看promise对象返回的结果,再根据promise对象返回的结果觉得是调用resolve还是reject
        */
       if(x instanceof MyPromise){
        // 是promise对象
        x.then(resolve, reject)
       } else {
         resolve(x)
       }
    }

    // then方法,内部就是做判断,如果状态成功调用成功的回调,如果状态失败则调用失败的回调
    then(onFulfilled, onRejected){
        const promise2 = new MyPromise((resolve, reject) => {
            if(this.status === FULFILLED){
                let x = onFulfilled(this.value)
                this.resolvePromise(x, resolve, reject)
            } else if(this.status === REJECTED){
                let x = onRejected(this.reason)
                this.resolvePromise(x, resolve, reject)
            } else {
                // 走到这里的原因是:主线程中的代码不会等到异步代码执行完再执行,而是立即执行的,因此异步情况下执行到then后状态还是padding,处在等待过程中。
                // 此时还没有执行resolve和reject,而程序又走到了then并且传入了onFulfilled或onRejected,因此需要将onFulfilled和onRejected存储起来,等待执行到resolve或reject之后再去执行onFulfilled和onRejected
                this.onFulfilled.push(() => {
                    let x = onFulfilled(this.value)
                    this.resolvePromise(x, resolve, reject)
                })
                this.onRejected.push(() => {
                    let x = onRejected(this.reason)
                    this.resolvePromise(x, resolve, reject)
                })
            }
        })
        return promise2
    }
  1. 链式调用后完整代码
// 使用常量来标示Promise三种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise{
    constructor(executor){
        // 设定初始状态为pending
        this.status = PENDING
        // 存储resoleve和reject回调传递的参数
        this.value = undefined
        this.reason = undefined

        // 存储成功onFulfilled和失败onRejected回调
        this.onFulfilled = []
        this.onRejected = []


        // 需要使用bind方法将this绑定,不然会获取不到当前实例中的值
        executor(this.resolve.bind(this), this.reject.bind(this))

    }
    // resolve方法,改变状态为成功,存储传入的参数
    resolve(value){
        if(!(this.status === PENDING)){
            return
        }
        this.status = FULFILLED
        this.value = value
        // 判断成功回调是否存在,如果存在执行它并传入value参数,每执行一个删除一个
        while(this.onFulfilled.length) this.onFulfilled.shift()()
    }
    // reject方法,改变状态为失败,存储传入的失败原因参数
    reject(reason){
        if(!(this.status === PENDING)){
            return
        }
        this.status = REJECTED
        this.reason = reason
        // 判断失败回调是否存在,如果存在执行它并传入reason参数,每执行一个删除一个
        while(this.onRejected.length) this.onRejected.shift()()
    }
    resolvePromise(x, resolve, reject){
        /*
        1、判断x的值是普通值还是promise对象
        2、如果是普通值直接调用resolve并传值进去
        3、如果是promise对象,查看promise对象返回的结果,再根据promise对象返回的结果觉得是调用resolve还是reject
        */
       if(x instanceof MyPromise){
        // 是promise对象
        x.then(resolve, reject)
       } else {
         resolve(x)
       }
    }

    // then方法,内部就是做判断,如果状态成功调用成功的回调,如果状态失败则调用失败的回调
    then(onFulfilled, onRejected){
        const promise2 = new MyPromise((resolve, reject) => {
            if(this.status === FULFILLED){
                let x = onFulfilled(this.value)
                this.resolvePromise(x, resolve, reject)
            } else if(this.status === REJECTED){
                let x = onRejected(this.reason)
                this.resolvePromise(x, resolve, reject)
            } else {
                // 走到这里的原因是:主线程中的代码不会等到异步代码执行完再执行,而是立即执行的,因此异步情况下执行到then后状态还是padding,处在等待过程中。
                // 此时还没有执行resolve和reject,而程序又走到了then并且传入了onFulfilled或onRejected,因此需要将onFulfilled和onRejected存储起来,等待执行到resolve或reject之后再去执行onFulfilled和onRejected
                this.onFulfilled.push(() => {
                    let x = onFulfilled(this.value)
                    this.resolvePromise(x, resolve, reject)
                })
                this.onRejected.push(() => {
                    let x = onRejected(this.reason)
                    this.resolvePromise(x, resolve, reject)
                })
            }
        })
        return promise2
    }
}

export default MyPromise

四、实现捕获错误以及catch方法

1. 在new一个Promise执行器函数executor中需要捕获错误
    constructor(executor){
        // 设定初始状态为pending
        this.status = PENDING
        // 存储resoleve和reject回调传递的参数
        this.value = undefined
        this.reason = undefined

        // 存储成功onFulfilled和失败onRejected回调
        this.onFulfilled = []
        this.onRejected = []

        try {
            // 需要使用bind方法将this绑定,不然会获取不到当前实例中的值
            executor(this.resolve.bind(this), this.reject.bind(this))
        } catch (error) {
            this.reject.call(this, error)
        }

    }
  1. 在then方法中需要捕获错误
    then(onFulfilled, onRejected){
        const promise2 = new MyPromise((resolve, reject) => {
            if(this.status === FULFILLED){
                try {
                    let x = onFulfilled(this.value)
                    this.resolvePromise(x, resolve, reject)
                } catch (error) {
                    reject(error)
                }
            } else if(this.status === REJECTED){
                try {
                    let x = onRejected(this.reason)
                    this.resolvePromise(x, resolve, reject)
                } catch (error) {
                    reject(error)
                }
            } else {
                // 走到这里的原因是:主线程中的代码不会等到异步代码执行完再执行,而是立即执行的,因此异步情况下执行到then后状态还是padding,处在等待过程中。
                // 此时还没有执行resolve和reject,而程序又走到了then并且传入了onFulfilled或onRejected,因此需要将onFulfilled和onRejected存储起来,等待执行到resolve或reject之后再去执行onFulfilled和onRejected
                this.onFulfilled.push(() => {
                    try {
                        let x = onFulfilled(this.value)
                        this.resolvePromise(x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
                this.onRejected.push(() => {
                    try {
                        let x = onRejected(this.reason)
                        this.resolvePromise(x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
            }
        })
        return promise2
    }
  1. 在then方法中将参数变成可选参数,为空时直接将上一步的结果给到下一个then的回调方法中
    then(onFulfilled, onRejected){
        // 将参数变成可选参数,为空时直接将上一步的结果给到下一个then的回调方法中
        onFulfilled = onFulfilled ? onFulfilled : value => value
        onRejected = onRejected ? onRejected : reason => { throw reason }
        const promise2 = new MyPromise((resolve, reject) => {
            if(this.status === FULFILLED){
                try {
                    let x = onFulfilled(this.value)
                    this.resolvePromise(x, resolve, reject)
                } catch (error) {
                    reject(error)
                }
            } else if(this.status === REJECTED){
                try {
                    let x = onRejected(this.reason)
                    this.resolvePromise(x, resolve, reject)
                } catch (error) {
                    reject(error)
                }
            } else {
                // 走到这里的原因是:主线程中的代码不会等到异步代码执行完再执行,而是立即执行的,因此异步情况下执行到then后状态还是padding,处在等待过程中。
                // 此时还没有执行resolve和reject,而程序又走到了then并且传入了onFulfilled或onRejected,因此需要将onFulfilled和onRejected存储起来,等待执行到resolve或reject之后再去执行onFulfilled和onRejected
                this.onFulfilled.push(() => {
                    try {
                        let x = onFulfilled(this.value)
                        this.resolvePromise(x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
                this.onRejected.push(() => {
                    try {
                        let x = onRejected(this.reason)
                        this.resolvePromise(x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
            }
        })
        return promise2
    }

4.添加catch方法

    catch(failCallback){
        return this.then(undefined, failCallback)
    }
  1. 错误捕获后完整代码
// 使用常量来标示Promise三种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise{
    constructor(executor){
        // 设定初始状态为pending
        this.status = PENDING
        // 存储resoleve和reject回调传递的参数
        this.value = undefined
        this.reason = undefined

        // 存储成功onFulfilled和失败onRejected回调
        this.onFulfilled = []
        this.onRejected = []

        try {
            // 需要使用bind方法将this绑定,不然会获取不到当前实例中的值
            executor(this.resolve.bind(this), this.reject.bind(this))
        } catch (error) {
            this.reject.call(this, error)
        }

    }
    // resolve方法,改变状态为成功,存储传入的参数
    resolve(value){
        if(!(this.status === PENDING)){
            return
        }
        this.status = FULFILLED
        this.value = value
        // 判断成功回调是否存在,如果存在执行它并传入value参数,每执行一个删除一个
        while(this.onFulfilled.length) this.onFulfilled.shift()()
    }
    // reject方法,改变状态为失败,存储传入的失败原因参数
    reject(reason){
        if(!(this.status === PENDING)){
            return
        }
        this.status = REJECTED
        this.reason = reason
        // 判断失败回调是否存在,如果存在执行它并传入reason参数,每执行一个删除一个
        while(this.onRejected.length) this.onRejected.shift()()
    }
    resolvePromise(x, resolve, reject){
        /*
        1、判断x的值是普通值还是promise对象
        2、如果是普通值直接调用resolve并传值进去
        3、如果是promise对象,查看promise对象返回的结果,再根据promise对象返回的结果觉得是调用resolve还是reject
        */
       if(x instanceof MyPromise){
        // 是promise对象
        x.then(resolve, reject)
       } else {
         resolve(x)
       }
    }

    // then方法,内部就是做判断,如果状态成功调用成功的回调,如果状态失败则调用失败的回调
    then(onFulfilled, onRejected){
        // 将参数变成可选参数,为空时直接将上一步的结果给到下一个then的回调方法中
        onFulfilled = onFulfilled ? onFulfilled : value => value
        onRejected = onRejected ? onRejected : reason => { throw reason }
        const promise2 = new MyPromise((resolve, reject) => {
            if(this.status === FULFILLED){
                try {
                    let x = onFulfilled(this.value)
                    this.resolvePromise(x, resolve, reject)
                } catch (error) {
                    reject(error)
                }
            } else if(this.status === REJECTED){
                try {
                    let x = onRejected(this.reason)
                    this.resolvePromise(x, resolve, reject)
                } catch (error) {
                    reject(error)
                }
            } else {
                // 走到这里的原因是:主线程中的代码不会等到异步代码执行完再执行,而是立即执行的,因此异步情况下执行到then后状态还是padding,处在等待过程中。
                // 此时还没有执行resolve和reject,而程序又走到了then并且传入了onFulfilled或onRejected,因此需要将onFulfilled和onRejected存储起来,等待执行到resolve或reject之后再去执行onFulfilled和onRejected
                this.onFulfilled.push(() => {
                    try {
                        let x = onFulfilled(this.value)
                        this.resolvePromise(x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
                this.onRejected.push(() => {
                    try {
                        let x = onRejected(this.reason)
                        this.resolvePromise(x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
            }
        })
        return promise2
    }
    catch(failCallback){
        return this.then(undefined, failCallback)
    }
}

export default MyPromise

五、静态方法Promise.all()和Promise.resolve()实现

1. Promise.all
  • 允许我们按照异步代码调用的顺序得到异步的结果
  • Promise.all方法必须要所有的都成功,如果有其中一个失败了就算失败

代码如下:

    static all(array){
        // 用来返回成功的回调
        const result = []
        // 用来记录执行了数组中的第几个
        let index = 0
        return new Promise((resolve, reject) => {
            function addData(key, value){
                result[key] = value
                index++
                if(index === array.length){
                    resolve(result)
                }
            }
            for(let i = 0; i<array.length; i++){
                let current = array[i]
                if(current instanceof MyPromise){
                    current.then(value => {
                        addData(i, value)
                    }, reason => reject(reason))
                } else {
                    addData(i, current)
                }
            }
        })
    }
  1. resolve方法实现
  • resolve返回值会是一个Promise对象

代码如下:

    static resolve(value){
        // 如果是promise对象就直接返回,若不是则new一个Promise返回,执行原型上的resolve方法
        if(value instanceof MyPromise) return value
        return new MyPromise(resolve => resolve(value))
    }

六、实现finally方法

代码如下:
    finally(callback){
        return this.then((value) => {
            return MyPromise.resolve(callback()).then(() => value)
        }, reason => {
            return MyPromise.resolve(callback()).then(() => {throw reason})
        })
    }

七、完整代码

// 使用常量来标示Promise三种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise{
    static all(array){
        // 用来返回成功的回调
        const result = []
        // 用来记录执行了数组中的第几个
        let index = 0
        return new Promise((resolve, reject) => {
            function addData(key, value){
                result[key] = value
                index++
                if(index === array.length){
                    resolve(result)
                }
            }
            for(let i = 0; i<array.length; i++){
                let current = array[i]
                if(current instanceof MyPromise){
                    current.then(value => {
                        addData(i, value)
                    }, reason => reject(reason))
                } else {
                    addData(i, current)
                }
            }
        })
    }
    static resolve(value){
        // 如果是promise对象就直接返回,若不是则new一个Promise返回,执行原型上的resolve方法
        if(value instanceof MyPromise) return value
        return new MyPromise(resolve => resolve(value))
    }
    constructor(executor){
        // 设定初始状态为pending
        this.status = PENDING
        // 存储resoleve和reject回调传递的参数
        this.value = undefined
        this.reason = undefined

        // 存储成功onFulfilled和失败onRejected回调
        this.onFulfilled = []
        this.onRejected = []

        try {
            // 需要使用bind方法将this绑定,不然会获取不到当前实例中的值
            executor(this.resolve.bind(this), this.reject.bind(this))
        } catch (error) {
            this.reject.call(this, error)
        }

    }
    // resolve方法,改变状态为成功,存储传入的参数
    resolve(value){
        if(!(this.status === PENDING)){
            return
        }
        this.status = FULFILLED
        this.value = value
        // 判断成功回调是否存在,如果存在执行它并传入value参数,每执行一个删除一个
        while(this.onFulfilled.length) this.onFulfilled.shift()()
    }
    // reject方法,改变状态为失败,存储传入的失败原因参数
    reject(reason){
        if(!(this.status === PENDING)){
            return
        }
        this.status = REJECTED
        this.reason = reason
        // 判断失败回调是否存在,如果存在执行它并传入reason参数,每执行一个删除一个
        while(this.onRejected.length) this.onRejected.shift()()
    }
    resolvePromise(x, resolve, reject){
        /*
        1、判断x的值是普通值还是promise对象
        2、如果是普通值直接调用resolve并传值进去
        3、如果是promise对象,查看promise对象返回的结果,再根据promise对象返回的结果觉得是调用resolve还是reject
        */
       if(x instanceof MyPromise){
        // 是promise对象
        x.then(resolve, reject)
       } else {
         resolve(x)
       }
    }

    // then方法,内部就是做判断,如果状态成功调用成功的回调,如果状态失败则调用失败的回调
    then(onFulfilled, onRejected){
        // 将参数变成可选参数,为空时直接将上一步的结果给到下一个then的回调方法中
        onFulfilled = onFulfilled ? onFulfilled : value => value
        onRejected = onRejected ? onRejected : reason => { throw reason }
        const promise2 = new MyPromise((resolve, reject) => {
            if(this.status === FULFILLED){
                try {
                    let x = onFulfilled(this.value)
                    this.resolvePromise(x, resolve, reject)
                } catch (error) {
                    reject(error)
                }
            } else if(this.status === REJECTED){
                try {
                    let x = onRejected(this.reason)
                    this.resolvePromise(x, resolve, reject)
                } catch (error) {
                    reject(error)
                }
            } else {
                // 走到这里的原因是:主线程中的代码不会等到异步代码执行完再执行,而是立即执行的,因此异步情况下执行到then后状态还是padding,处在等待过程中。
                // 此时还没有执行resolve和reject,而程序又走到了then并且传入了onFulfilled或onRejected,因此需要将onFulfilled和onRejected存储起来,等待执行到resolve或reject之后再去执行onFulfilled和onRejected
                this.onFulfilled.push(() => {
                    try {
                        let x = onFulfilled(this.value)
                        this.resolvePromise(x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
                this.onRejected.push(() => {
                    try {
                        let x = onRejected(this.reason)
                        this.resolvePromise(x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
            }
        })
        return promise2
    }
    finally(callback){
        return this.then((value) => {
            return MyPromise.resolve(callback()).then(() => value)
        }, reason => {
            return MyPromise.resolve(callback()).then(() => {throw reason})
        })
    }
    catch(failCallback){
        return this.then(undefined, failCallback)
    }
}

export default MyPromise