二、实现Promise

// MyPromise 的状态值,只有三种,定义成常量,方便复用,并且有代码提示方便编码
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败

class MyPromise {
    constructor(executor) {  // 创建一个立即执行的执行器
        try {  // 对执行器进行错误捕获
            executor(this.resolve, this.reject)  // 立即执行
        } catch (e) {
            this.reject(e);
        }
    }

    // 定义实例属性:每一个实例都有自己的实例状态和成功的值和失败的原因 
    status = PENDING;   // 状态
    value = undefined;  // 成功之后的值
    reason = undefined; // 失败后的原因

    // 定义实例属性:存储状态确定后的回调,为了能同时存储多个回调所以用数组
    successCallback = [];   // 成功FULFILLED的回调
    failCallback = [];      // 失败REJECTED的回调

    resolve = value => { // 用箭头函数来保证内部的this指向当前MyPromise的实例
        // 如果状态不是PENDING就阻止程序向下执行(因为状态一旦确定就不会再变了)
        if (this.status !== PENDING) return;
        this.status = FULFILLED;    // 将状态更改为成功
        this.value = value;        // 保存成功之后的值

        // 判断成功回调是否存在 如果存在 调用
        // this.successCallback && this.successCallback(this.value);
        while (this.successCallback.length) this.successCallback.shift()()
    }

    reject = reason => {
        // 如果状态不是PENDING就阻止程序向下执行(因为状态一旦确定就不会再变了)
        if (this.status !== PENDING) return;
        this.status = REJECTED; // 将状态更改为失败
        this.reason = reason;   // 保存失败后的原因

        // 判断失败回调是否存在(也就是数组长度是否为0),如果存在就调用
        // 循环数组中的值,不断用shift将数组元素弹出数组,并执行弹出的元素(元素就是存的回调函数)直到数组长度为0
        while (this.failCallback.length) this.failCallback.shift()()
    }

    then(successCallback, failCallback) {
        // 实现参数可选,如果没有successCallback就补一个,将上一个promise中的值向下传递
        successCallback = successCallback ? successCallback : value => value;
        // 实现参数可选,如果没有failCallback就补一个,将上一个promise中的值向下传递
        failCallback = failCallback ? failCallback : reason => {
            throw reason
        };
        // 因为then返回的是一个promise对象,所以需要先建立一个promise并返回
        let promsie2 = new MyPromise((resolve, reject) => { // 这里面是立即执行的
            // 对状态进行判断(包含同步异步的判断,前两个是同步的,最后一个else是异步)
            if (this.status === FULFILLED) {    // 同步 =>成功的状态FULFILLED
                // 这里要注意,then返回的promise使用的是实例状态,默认值是PENDING
                setTimeout(() => { // 这里如果不改成异步那么promise2是在new执行中获取的,显然获取不到
                    try {
                        let x = successCallback(this.value); // 拿到上一个then的返回值
                        // 调用这个内部的promise的resolve,就是把resolve的返回值传递给下一个then了

                        resolvePromise(promsie2, x, resolve, reject)
                        // 判断 x 的值是普通值还是promise对象,如果是普通值 直接调用resolve 
                        // 如果是promise对象 查看promsie对象返回的结果
                        // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
                    } catch (e) { 
                        reject(e);
                    }
                }, 0)
            } else if (this.status === REJECTED) {  // 同步 =>失败的状态REJECTED
                setTimeout(() => { 
                    try {
                        let x = failCallback(this.reason);
                        // 判断 x 的值是普通值还是promise对象,如果是普通值 直接调用resolve 
                        // 如象果是promise对 查看promsie对象返回的结果 
                        // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
                        resolvePromise(promsie2, x, resolve, reject)
                    } catch (e) {
                        reject(e);
                    }
                }, 0)
            } else {    // 异步等待的状态,等有状态变了再去执行对应的回调
                        // 所以需要将成功回调和失败回调存储起来,等状态确定了再调用
                this.successCallback.push(() => {  // 异步 =>将成功的回调存到数组中
                    setTimeout(() => {
                        try {   // 使用try...catch来捕获错误
                            let x = successCallback(this.value);
                            // 判断 x 的值是普通值还是promise对象,如果是普通值 直接调用resolve 
                            // 如果是promise对象 查看promsie对象返回的结果 
                            // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
                            resolvePromise(promsie2, x, resolve, reject)
                        } catch (e) {
                            reject(e);
                        }
                    }, 0)
                });
                this.failCallback.push(() => {  // 异步 =>将失败的回调存到数组中
                    setTimeout(() => {
                        try {  // 使用try...catch来捕获错误
                            let x = failCallback(this.reason);
                            // 判断 x 的值是普通值还是promise对象,如果是普通值 直接调用resolve 
                            // 如果是promise对象 查看promsie对象返回的结果 
                            // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
                            resolvePromise(promsie2, x, resolve, reject)
                        } catch (e) {
                            reject(e);
                        }
                    }, 0)
                });
            }
        });
        return promsie2;
        // 因为then返回的是一个promise对象,所以需要先建立一个promise并返回
    }

    finally(callback) { // 无论成功还是失败都要调用
        return this.then(value => {
            return MyPromise.resolve(callback()).then(() => value);
        }, reason => {
            return MyPromise.resolve(callback()).then(() => {
                throw reason
            })
        })
    } 
    
    catch (failCallback) {  // 直接复用then和failCallback方法来捕获错误。
        return this.then(undefined, failCallback)
    }

    // 静态方法:MyPromise.all
    static all(array) {
        let result = [];
        let index = 0;
        return new MyPromise((resolve, reject) => {
            function addData(key, value) {
                result[key] = value;
                index++;
                if (index === array.length) {
                    resolve(result);  // 在都执行完了后才能调用result
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                if (current instanceof MyPromise) {
                    // 判断,如果是promise 对象就执行promise对象
                    // 并且,如果有一个返回了reject,那么整个all都走reject
                    current.then(value => addData(i, value), reason => reject(reason))
                } else {
                    // 普通值
                    addData(i, array[i]);
                }
            }
        })
    }

    // 静态方法:MyPromise.resolve 
    static resolve(value) {     // 首先判断是不是promise对象
        if (value instanceof MyPromise) return value;  // 如果是promise就直接返回
        return new MyPromise(resolve => resolve(value)); // 如果不是就将其包装进promise
    }

    // 静态方法:MyPromise.reject
    static reject(value) {     // 首先判断是不是promise对象
        if (value instanceof MyPromise) return value;  // 如果是promise就直接返回
        return new MyPromise((resolve,reject) => reject(value)); // 如果不是就将其包装进promise
    }

    // 静态方法:MyPromise.race
    static race (value) {
        let arr = Array.from(value)  // 传递进来的参数可以是个类数组,后续操作将其转换为真数组
        return new MyPromise(function(resolve, reject) {
            for (let i = 0,len = arr.length; i < len; i++) {  // 遍历数组,执行回调
                MyPromise.resolve(arr[i]).then(value => { 
                    resolve(value)
                }, reason => {
                    return reject(reason)
                })
            }
        })
    }
    
}

// 把判断then返回值的方法抽离出来
function resolvePromise(promsie2, x, resolve, reject) {
    if (promsie2 === x) {  // 如果返回的是自身,那就抛出一个错误
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if (x instanceof MyPromise) {  // 如果返回的是promise那就把回调值改成当前promise调用then
        // promise 对象
        // x.then(value => resolve(value), reason => reject(reason));
        x.then(resolve, reject);  // 由于上述具有之前封装的resolve和reject方法的格式,所以简化直接用
    } else {    // 如果返回的是普通值,那就直接调用resolve(x)
        // 普通值
        resolve(x);
    }
}

module.exports = MyPromise;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值