手写promise

135 阅读5分钟

promise.js

/**
 * 第一步:
 *      1. promise 接受一个执行器参数,该执行器以一个两个参数resolve, reject
 *        执行器是创建对象立即执行的, 所以执行器实在构造函数里
 * 
 *      2. 状态:三种分别是, 状态字符串, 可以定义成常量, 在
 *               pedding:    等待中  
 *               fulfilled:   成功
 *               rejected:    失败
 *         状态可以从:pedding --> fulfilled, 或者 pedding --> rejected,
 *         状态一旦确定, 就不可在改变
 *      3. 执行器里面的resolve, reject 方法执行时, 就会改变对应的状态的, 状态是需要保存的, 定义保存status
 *                  resolve:  pedding --> fulfilled, 该方法是处理成功的, 
 *                           接受一个成功数据参数value(异步操作的结果), value是在then 方法的第一个参数(函数参数)里使用的
 *         reject:  pedding -->rejected    该方法是处理失败的
 *                 接受一个失败数据参数reason(异步操作失败的原因), reason,是在then 方法的第二个参数(函数参数)里使用的
 * 
 *      4. then: 该方法内部判断状态, 如果是成功状态, 就执行成功回调函数(successCallBack), 如果失败就调用失败回调函数(failCallBack), 该方法是prosie对象调用, 所以直接定义在原型对象(MyPromisele类)中
 *                successCallBack: 接受一个参数:操作成功之后的值, 分同步,异步操作两种情况
 *                failCallBack: 接受一个参数, 操作失败的原因,  分同步,异步操作两种情况
 *               可以被调用多次, 也就是successCallBack, failCallBack的存储是一个数组
 *              then方法是可以被链式调用的, 后面then方法的回调函数拿到值的是上一个then方法的回调函数的返回值,
 *              回调函数返回值, 不能自己返回自己
 * 
 *  第二步:all : 并行执行
 *         catch
 *         resolve 
 *         catch
 *         finally
 */
const PEDDING = 'pedding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class Mypromsie {
    constructor (excutor) {
        excutor(this.resolve, this.reject)  // 接受两个参数分别是  resolve, reject, 在Mypromsie类定义这两个属性
    }
    status = PEDDING // 默认值
    _value = undefined // 保存成功的值
    _reason = undefined // 保存失败的原因
    successCallBack = [] // then 里注册的成功回调函数
    failCallBack = []  // then 里注册的失败回调函数
    resolve = value =>  {    // then 回调函数中会使用value 所以保存起来
        if (!Object.is(this.status, PEDDING)) return   // 状态一旦确定就不可在变化
        this.status = FULFILLED
        this._value = value
        while(this.successCallBack.length) { // 如果存在, 则是异步操作
        //     this.successCallBack(this._value)
            this.successCallBack.shift()() // 传递的函数里含有this.value所以这里不需要了
        }
    }
    reject = reason => {  // then 回调函数中会使用reason 所以保存起来
        if (!Object.is(this.status, PEDDING)) return   // 状态一旦确定就不可在变化
        this.status = REJECTED
        this._reason = reason
        while(this.failCallBack.length) { // 如果存在, 则是异步操作
            this.failCallBack.shift()()
         }
    }
    then(successCallBack, failCallBack) { // 分同步操作, 和异步操作分别处理
        const promise2 = new Promise((resolve, reject) => {  // successCallBack,failCallBack的返回值,promsie2的resolve, reject方法的的参数值一直传递下去 
            if (Object.is(this.status, FULFILLED)) {
                // 这里 promise2 还没有初始化, 所以这里拿不到, 所以这里 使用异步,让其先初始化
                setTimeout(() => { 
                    try {
                        const x = successCallBack(this._value) // 异步操作成功的值, 传给成功回调, 同步操作情况下, 同步情况下, 回调函数直接执行, 不需要存储到数组
                        resolvePromise(promise2, x, resolve, reject) // successCallBack的回调函数的返回值, 被传递到resolve方法中
                    } catch (e) { // 捕获异常, 执行reject
                        reject(e)
                     }
                }, 0)
            } else if (Object.is(this.status, REJECTED)) {
                setTimeout(() => { 
                    try {
                        const x = failCallBack(this._reason)  // 异步操作失败的值, 传给失败回调, 同步操作情况下,同步情况下, 回调函数直接执行, 不需要存储到数组
                        resolvePromise(promise2, x, resolve, reject) // successCallBack的回调函数的返回值, 被传递到resolve方法中
                    } catch (e) { // 捕获异常, 执行reject
                        reject(e)
                     }
                }, 0)
                if (successCallBack) {  
                    this.successCallBack.push(() => { 
                        setTimeout(() => {
                            try {
                                const x = successCallBack(this._value)
                                resolvePromise(promise2, x, resolve, reject) // successCallBack的回调函数的返回值, 被传递到resolve方法中
                            } catch (e) { // 捕获异常, 执行reject
                                reject(e)
                             }
                         }, 0)
                    }) // 这里不能像上面的successCallBack那样直接获取返回值(因为状态还没有该拜年), 利用高阶函数,返回一个函数,就行
                }
                if (failCallBack) { 
                    this.failCallBack.push(() => { 
                        setTimeout(() => {
                            try {
                                const x = failCallBack(this._reason)
                                resolvePromise(promise2, x, resolve, reject) // successCallBack的回调函数的返回值, 被传递到resolve方法中
                            } catch (e) { // 捕获异常, 执行reject
                                reject(e)
                             }
                         }, 0)
                    })
                }
            }
        })
        return promise2 // 返回promise以实现then 的链式调用
    }
    // 捕获整个promise链的异常
    catch(failCallBack) {
        return this.then(undefined, failCallBack)
    }
    /**
     * @param {*} callback
     * @memberof Mypromsie
     * 不管是成功,还是失败都会执行这个方法
     */
    finally(callback) { 
        return this.then(value => {
            return new Mypromsie.resolve(callback()).then(() => value)
        }, reason => { 
                return new Promise.resolve(callback()).then(() => { 
                    throw reason
                })
        })
    } 
    /**
     * @static
     * @param {*} array promise 数组
     * @memberof Mypromsie
     * @return  返回的也是一个promise
     * 数组的promise必须全部完成, 这个promise才完成
     */
    static all(array) {
        let result = [] // promise 的执行结果
        let index = 0  // 第几个promsie
        return new Mypromsie((resolve, reject) => { 
            // 把promise的处理结果, 添加进数组
            function addData(_index, data) {
                result[_index, data] // promise 的执行期可能不是同步的, 所以不能使用Push
                ++index 
                if (result.length === index) { // 数组的长度和inde长度一致吗, 说明所有promise 都执行完成了
                    resolve(result)
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i]
                if (current instanceof Mypromsie) {
                    // Mypromise 对象
                    current.then(value => {
                        addData(i, value) // 添加
                    }, reason => {
                        reject(reason) // 整个promise 结束
                    })
                } else { // 普通值, 直接添加
                    addData(i, current)
                }
            }
        })
    }
    /**
     * @static
     * @param {*} value
     * @returns
     * @memberof Mypromsie
     * 如果是promise 就直接返回
     * 如果是普通对象, 则包裹成promsie 
     */
    static resolve(value) {
        if (value instanceof Mypromsie) return value
        return new Mypromsie(resolve => resolve(value))
     }
}
/**
     *
     *
     * @param {*} 调用的promise
     * @param {*} 返回的值
     * @param {*} resolve
     * @param {*} reject
     * @return 
     * @memberof Mypromsie
     * 如果是普通值 直接调用resolve 
     * 如果是promise对象 查看promsie对象返回的结果 
     * 再根据promise对象返回的结果 决定调用resolve 还是调用reject
     */
    function resolvePromise(promise, x, resolve, reject) { 
        if (promise === x) { // 防止自己返回自己, 造成死循环 
            return reject(new Error('Chaining cycle detected for promise #<Promise>'))
        }
        //then 返回的是 promise 对象
        // 则 返回x.then(valuie => resolve(x), reason => reject(reason))
        if (x instanceof Mypromsie) {
            x.then(resolve, reject) // 简写
        } else { 
            resolve(x) // 普通值
        }
    }
module.exports = Mypromsie // 导出

测试文件test.js

/**
 *  测试
 */
const MyPromise = require('./myPromise')
const promise = new MyPromise((resolve, reject) => {
    // resolve('测试成功')                  // 测试成功 
    // reject(new Error('测试失败 error'))     // 测试失败
    // reject(new Error('测试状态不可以在改变 error'))     // 测试状态不可以在改变

    // setTimeout(() => { 
    //     // resolve('测试异步成功')    
    //     reject(new Error('测试异步失败'))    
    // }, 1000)
    reject(new Error('catch'))
})

// promise.then(res => {
//     // console.log('res', res)
//     setTimeout(() => {
//         console.log('then1', res)
//     }, 1000)
//     return '测试then的链式调用'
// }, reason => {
//     console.log('reason', reason.message)
    
// })
// .then(res => { 
//     console.log(res)
// })

// promise.then(res => { // 测试连续调用h then
//     setTimeout(() => {
//         console.log('then', res)
//     }, 2000)
// }, reason => {
//     console.log('reason', reason.message)
// })
const promise2 = promise.then(value => { 
    console.log('promise2', value)
}, reason => {
    console.log('reject', reason)  
})
promise.catch(reason => { // 测试catch
    console.log('catch', reason)  
}).finally(() => { 
    console.log('finally')  
})