手写Promise源码-源码(2)

60 阅读4分钟
//Promise/A+规范的三种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
    constructor(executor) {
        // 为传入的执行器再传入两个函数。执行器是立即执行的,所以New Promise操作内部代码是同步的
        try {
            executor(this.resolve, this.reject)
        } catch (error) {
            this.reject(error)
        }
    }
    // promise 状态默认为等待状态
    status = PENDING
    // 成功之后的值
    value = undefined
    // 失败后的原因
    reason = undefined
    /**
     * successCallback和failCallback,它们存储的是针对于异步任务的回调函数
     */
    // 存储成功回调的队列
    successCallback = []
    // 存储失败回调的队列
    failCallback = []
    /**
     * 
     * 使用箭头函数原因:
     * 我们是直接调用这些方法的,那么this可能会指向window或者undefined
     * 使用箭头函数则会将this指向通过Promise构造的对象,而我们的方法内部会要获取该this对象上的方法
     * 
     * resolve、reject会接受成功的值和失败的原因
     * 
     * 这些方法被定义在了实例对象上
     */
    resolve = (value) => {
        if (this.status !== PENDING) return   // 对应规范中的"状态只能由pending到fulfilled或rejected"
        this.status = FULFILLED // 变更状态
        // 保存成功的值
        this.value = value;
        // 判断成功回调是否存在,如果有则调用并传入值
        // this.successCallback && this.successCallback(this.value);
        while (this.successCallback.length) {
            const callback = this.successCallback.shift();
            // 这里不再需要传值,因为已在then方法中处理
            // callback(this.value);
            callback();
        }
    }
    reject = (reason) => {
        if (this.status !== PENDING) return   // 对应规范中的"状态只能由pending到fulfilled或rejected"
        this.status = REJECTED // 变更状态
        // 保存失败的原因
        this.reason = reason;
        // 判断失败回调是否存在,如果有则调用并传入失败原因
        // this.failCallback && this.failCallback(this.reason);
        while (this.failCallback.length) {
            const callback = this.failCallback.shift();
            // 这里不再需要传值,因为已在then方法中处理
            // callback(this.reason);
            callback();
        }
    }
    // then方法只被promise对象调用,所以不用为箭头函数?此时被定义在了原型上
    then(successCallback, failCallback) {
        // 判空处理,补充默认值
        successCallback = (successCallback && typeof successCallback === 'function') ? successCallback : value => value;
        failCallback = (failCallback && typeof failCallback === 'function') ? failCallback : reason => { throw reason };
        // 这里创建的Promise会立即执行,所以基本和之前无变化,只是返回了一个Promise对象,实现了链式调用。
        let thenPromise = new MyPromise((resolve, reject) => {
            switch (this.status) {
                // 对于异步任务,先存储进各自的回调队列,当执行了resolve或reject方法后,再取出回调进行调用
                case PENDING:
                    // 我们这里要兼容异步任务,并对回调同样要进行报错处理
                    // 老代码-不兼容异步处理
                    // let x = successCallback(this.value);
                    // resolvePromise(thenPromise, x, resolve, reject);
                    // 新代码-兼容异步处理
                    this.successCallback.push(() => {
                        setTimeout(() => {
                            try {
                                let x = successCallback(this.value);
                                resolvePromise(thenPromise, x, resolve, reject);
                            } catch (error) {
                                reject(error)
                            }
                        }, 0);
                    });
                    this.failCallback.push(() => {
                        setTimeout(() => {
                            try {
                                let x = failCallback(this.reason);
                                resolvePromise(thenPromise, x, resolve, reject);
                            } catch (error) {
                                reject(error)
                            }
                        }, 0);
                    });
                    break;
                // 对于同步任务,已经改变了状态,直接执行回调
                case FULFILLED:
                    /**
                     * 实现then链式调用:
                     * 获取上个then返回值,用一个变量接收
                     * 在这个Promise中调用它的resolve或reject,就能被下一个.then()的回调获取到返回值,从而实现链式调用。
                     * 
                     * 保证执行顺序:
                     * 所以还要分类讨论返回值,如果是Promise,那么等待Promise状态变更,否则直接resolve
                     */
                    setTimeout(() => {
                        try {
                            let x = successCallback(this.value);
                            resolvePromise(thenPromise, x, resolve, reject);
                        } catch (error) {
                            reject(error)
                        }
                    }, 0);
                    break;
                case REJECTED:
                    setTimeout(() => {
                        try {
                            let x = failCallback(this.reason);
                            resolvePromise(thenPromise, x, resolve, reject);
                        } catch (error) {
                            reject(error)
                        }
                    }, 0);
                    break;
            }
        })
        return thenPromise;
    }
    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);
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(value => addData(i, value), error => reject(error))
                } else {
                    // 普通值
                    addData(i, array[i]);
                }
            }
        })
    }
    static race(array) {
        return new Promise((resolve, reject) => {
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                if (current instanceof MyPromise) {
                    current.then(value => resolve(value), error => reject(error))
                } else {
                    resolve(array[i])
                }
            }
        })
    }
    static resolve(value) {
        if (value instanceof MyPromise) return value;
        return new MyPromise(resolve => resolve(value));
    }
    static reject(reason) {
        if (reason instanceof MyPromise) return reason;
        return new MyPromise((resolve, reject) => reject(reason))
    }
    finally(callback) {
        /**
         * 获取当前状态:
         * this对象上的then方法能获取到状态
         * 
         * 成功失败都会执行finally的回调方法
         * 
         * 链式调用:
         * then方法会返回promise,实现回调
         */
        return this.then((value) => {
            // todo好好理解z
            return MyPromise.resolve(callback()).then(() => value);
        }, (reason) => {
            // 通过throw 传递失败原因
            return MyPromise.resolve(callback()).then(() => {throw reason});
        })
    }
    catch(failCallback) {
        // 只注册失败回调
        return this.then(undefined, failCallback)
    }
}
/**
 * 判断 x 的值是普通值还是promise对象
 * 如果是普通值直接调用resolve 
 * 如果是promise对象 查看promsie对象返回的结果 
 * 再根据promise对象返回的结果 决定调用resolve 还是调用reject
 * 放在外面是为了不让使用者调用这个方法吗?
 */
function resolvePromise(thenPromise, x, resolve, reject) {
    if (thenPromise === x) {
        // return 阻止代码继续运行
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
    }
    // 所以如果链式调用then方法,不传入Promise,那么它就会原样不动以类似val => val形式传递下去
    try {
        // 在错误回调中返回值为什么会调用下个.then的成功回调?
        // 原因就在这,会调用resolve方法
        x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
    } catch (error) {
        reject(error);
    }
}
module.exports = MyPromise;