深入javascript_手写Promise

手写Promise

分析:

  1. promise是一个类, 传入参数是回调函数(执行器),函数会立即执行
  2. promise有三种状态,分别是等待 PENDING 成功 FULFILLED 失败RJECKTED,且一旦由pending转为另外两种状态之后不得更改
  3. 在执行器中调用 resolve 和reject函数是用来更改状态的 从pending-> fulfilled 或者从pending-> rejected
  4. 传递给resolve 就是成功传递的值 , 传给reject的就是失败的原因
    5 .then 方法内部做的事情就是判断状态 成功的话调用成功的回调函数,失败的话调用失败的回调函数,另外then方法是promise原型对象上的方法
  5. 当前状态为等待就是异步的时候我们不知道执行失败还是成功 ,所以把失败和成功的回调函数保存起来,在 resolve和rekect中判断 失败回调和成功回调是否有,存在就执行并传参
  6. then方法的链式调用每个都要返回一个proimise对象, 和把上一个返回值给下一个then方法
  7. then中不能返回当前的promise对象,会导致promise对象的循环调用
// 5. 定义 promise的3中状态为常量  这三种状态的值不会改变了所以定义为常量
const PENDING = 'penging';
const FULFILLED = 'fulfilled';
const RJECKTED = 'rejected';

//  定义一个MyPromise的类
class MyPromise {
    //     接收执行器
    constructor(exector) {
        //  立即调用执行器,并传递两个回调函数的参数 resolve,reject
        exector(this.resolve, this.reject)
    }
    status = PENDING //  设置初始状态为PENDING
    // 定义成功的参数 和失败的原因
    value = undefined; // 成功后的值
    reason = undefined; // 失败后的值

    // successCallcack = undefined // 保存成功回调函数 
    // failCallback = undefined // 保存失败回调函数 

    successCallcack = [] // 链式保存成功回调函数数组
    failCallback = [] // 链式保存失败回调函数数组
    //  定义 resolve,reject 定义为箭头函数的原因是想让内部this的指向指向MyPromise对象 因为这两个函数是直接调用的
    resolve = value => {
        // 判断状态是否是等待 等待的话就return
        if (this.status != PENDING) return
        //更改为成功状态
        this.status = FULFILLED
        // 保存成功之后的值
        this.value = value
        // 判断成功是否保存了成功回调函数,保存了就执行并传参
        // this.successCallcack && this.successCallcack(this.value)

        // 当前成功的回调还有成功回调就继续执行并删除 直到数组中没有成功的回调函数
        while (this.successCallcack.length) this.successCallcack.shift()()
    }

    reject = (reason) => {
        //  判断状态是否是等待 等待的话就return
        if (this.status != PENDING) return
        //  更改为失败状态
        this.status = RJECKTED
        // 保存失败后的原因
        this.reason = reason
        // 判断失败是否保存了失败回调函数,保存了就执行并传参
        // this.failCallback = this.failCallback(this.reason)


        // 当前失败的回调还有成功回调就继续执行并删除 直到数组中没有失败的回调函数
        while (this.failCallback.length) this.failCallback.shift()(this.reason)


    }
    //  promise的实例上有一个then方法 接收两个参数 成功和失败的回调函数
    then(successCallcack, failCallback) {
        successCallcack = successCallcack ? successCallcack : value => value
        failCallback = failCallback ? failCallback : reason => {
            throw reason
        }
        // 返回promise对象实现链式调用
        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                // 13成功 调用成功回调 并传给函数成功的值
                setTimeout(() => {
                    try {
                        let x = successCallcack(this.value)
                        // 传递给下个then方法的回调函数
                        // 如果当前的x 是普通值就传给下个对象,如果是promise对象就查看返回结果 根据结果判断调用resolve还是reject
                        // resolve(x)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            } else if (this.status === RJECKTED) {
                //  失败 调用失败回调 并传给函数失败的原因
                setTimeout(() => {
                    try {
                        let y = failCallback(this.reason)
                        // 传递给下个then方法的回调函数
                        reject(y)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            } else {
                // 处理异步 等待的状态的将失败或成功的回调保存起来
                // this.successCallcack = successCallcack
                // this.failCallback = failCallback

                // 多个异步then的链式编程所以successCallcack和failCallback应该是个数组
                // this.successCallcack.push(successCallcack)
                // this.failCallback.push(failCallback)

                //等待
                this.successCb.push(() => {
                    setTimeout(() => {
                        try {
                            let x = successCb(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                });
                this.failCb.push(() => {
                    setTimeout(() => {
                        try {
                            let x = failCb(this.err)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                });
            }
        })

        return promise2
        // . 链式编程中 then 中调用成功和失败的回调函数
    }


    // 其他方法

    catch (cb) {
        return this.then(undefined, cb)
    } finally(cb) {
        return this.then(value => {
            return MyPromise.resolve(cb()).then(() => value);
        }, err => {
            return MyPromise.resolve(cb()).then(() => {
                throw err
            })
        })
    }
    // 静态方法all
    static all(arr) {
        let result = [];
        let index = 0;

        return new MyPromise((resolve, reject) => {
            function addData(key, value) {
                result[key] = value;
                index++;
                if (index === arr.length) {
                    resolve(result)
                }
            }
            for (let i = 0; i < arr.length; i++) {
                let current = arr[i];
                if (current instanceof MyPromise) {
                    current.then(value => addData(i, value), err => reject(err))
                } else {
                    addData(i, arr[i])
                }
            }

        })
    }
    // 静态方法resolve
    static resolve(value) {
        // 判断传进来的value是不是属于MyPrimise对象 属于返回value 不属于返回一个新的MyPromise对象
        if (value instanceof MyPromise) {
            return value
        } else {
            return new MyPromise((resolve) => resolve(value))
        }
    }
}

function resolvePromise(promise2, x, resolve, reject) {
    // 返回重复引用的错误
    if (promise2 === x) {
        return reject(new TypeError('重复引用了'))
    }
    if (x instanceof MyPromise) {
        // x属于MyPromise对象调用then方法返回 resolve, reject
        // x.then(value => resolve(value), reason => reject(reason)))
        // 优化
        x.then(resolve, reject)
    } else {
        resolve(x)
    }

}




// module.export(MyPromise)
// 测试代码
let promise = new MyPromise((resolve, reject) => {
    // 正常调用传参
    resolve('成功')
    // reject('失败')

    //  处理异步
    // setTimeout(() => {
    //     resolve('成功')
    // }, 2000)

    // 处理多个then的异步
    // setTimeout(() => {
    //     resolve('成功')
    // }, 2000)
})
// 1. 可以成功的输出成功失败  也验证了状态一旦由pending更改为fulfilled之后不能改为rejected
// 2. 等待两秒后输出成功
// promise.then(value => {
//     console.log(value);
// }, reason => {
//     console.log(reason);
// })

// promise.then(value => {
//     console.log(value);
// }, reason => {
//     console.log(reason);
// })

// promise.then(value => {
//     console.log(value);
// }, reason => {
//     console.log(reason);
// })



// function other() {
//     return new MyPromise((resolve, reject) => {
//         resolve('other')
//     })
// }

// promise.then(value => {
//     console.log(value);
//     return other()
// }, reason => {
//     console.log(reason);
// })

// function p1() {
//     return new MyPromise((resolve) => {
//         setTimeout(() => {
//             resolve('p1')
//         }, 2000)
//     })
// }

// function p2() {
//     return new MyPromise((resolve) => {
//         resolve('p2')
//     })
// }

// p2().finally(()=>{
//     console.log('finally');

// }).then(res=>{
//     console.log(res);

// },err=>{
//     console.log(err);

// })
// MyPromise.all(['a', 'b', p1(), p2(), 'c']).then(res => {
//     console.log(res);

// })
// MyPromise.resolve(100).then(res => console.log(res))
// function other() {
//     return new MyPromise((resolve, reject) => {
//         resolve('other')
//     })
// }
// 当前promise对象重复调用
// let p1 = promise.then(value => {
//     // throw new Error('自定义then错误')
//     console.log(value);
//     // return p1;
// }, err => {
//     console.log(err);
//     return 1000
// })
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页