手写实现Promise源码

手写实现Promise源码

/**
 *手写实现MyPromise源码
 */
// promise的三种状态,这里为了方便使用定义为常量,这三个状态一旦确定就无法更改
const PENDING = 'pending'; // 请求状态为等待
const FULFILLED = 'fulfilled'; // 请求状态为成功
const REJECTED = 'rejected'; // 请求状态为失败

/**
 *  定义自定义promise类,promise是一个类
 * 1、因为是类所以定义这个promise类;
 * 2、promise对象中传入的是一个执行器(回调函数,需要立即执行,里面需要将类中的resolve和reject方法传递出去)
 * 3、需要根据promise的状态(这个状态是每个promise独有的,需要定义为实例属性)来判断调用哪个resolve还是reject
 * 4、then方法(原型对象上的方法)内部做的事情就是判断状态,如果成功则调用执行成功的回调函数,如果失败则调用执行失败的回调函数
 * 5、在then方法的成功失败回调函数中,需要把对应的返回值(在resolve和reject中处理)传给这两个函数中;
 * 6、为了解决promise执行器中的异步逻辑,即当状态为pending的时候,将成功回调和失败回调存储起来(定义为实例属性),然后在resolve和reject中判断这两个是否存在存在则执行
 * 7、因为同一个promise对象的then方法可以多次调用,分为两种情况(同步和异步),同步则立即执行回调函数即可,异步则需要存储起来,因此第六点中的成功回调和失败回调是个数组,需要逐一取出执行
 * 8、promise的then方法可以被链式调用,实现链式调用时因为其每个then方法都返回promise对象,其对应回调函数中返回值取决于上个then方法对应回调函数里的返回值,则需要判断这个返回值是否是普通值还是promise对象,是promise对象(不能是当前promise对象)则查看其返回结果,根据返回结果调用resolve还是reject
 * 9、 捕获promise中的错误,一个是在执行器中进行捕获,还有一个就是在then方法里的成功回调函数如果执行报错,需要在下个then方法中失败回调函数中捕获这个错误
 * 10、then方法中的参数是可选的,因此需要将对于返回值一层一层往下传递
 * 11、promise.all静态方法,传入数组返回的也是数组,
 * 12、promise.resolve静态方法会创建一个promise对象,将传入的参数包裹在这个promise对象里
 * 13、finally方法无论状态成功还是失败都会被执行一次 ,这个方法后面能链式调用then方法
 * 14、catch方法执行失败回调,也就只要在这个方法里调用then方法,只注册失败回调,没有注册成功回调,这个方法后面也能调用promise其他的方法,因此需要返回这个promise对象 
 */
class MyPromise {
    // 传递一个执行器,这个方法会立即执行
    constructor(executor) {
        try {
            // 将resolve和reject方法传递出去,因此需要在类中定义该方法
            executor(this.resolve, this.reject)
        } catch (e) {
            // 捕获异常错误
            this.reject(e);
        }
    }
    // promise 状态 这个状态是每个promise独有的,需要定义为实例属性
    status = PENDING;
    // 成功之后的值(每个promise对象都有成功之后的值,将其保存下来,定义为实例属性,默认值为undefined)
    value = undefined;
    // 失败后的原因
    reason = undefined;
    // 成功回调,因为promise可以多次调用then方法,所以用的是数组存储起来
    successCallback = [];
    // 失败回调,因为promise可以多次调用then方法,所以用的是数组存储起来
    failCallback = [];
    // 定义resolve方法,参数value是返回值,使用箭头函数的原因是为了处理方法中this的指向问题,这里指向promise对象
    resolve = value => {
        // 判断如果状态不是等待,则阻止程序向下执行,防止更改promise状态
        if (this.status !== PENDING) return;
        // 将状态更改为成功
        this.status = FULFILLED;
        // 保存成功之后的值
        this.value = value;
        // 判断成功回调是否存在 如果存在 调用(因为then方法可以多次调用,需要存储对应回调,取出执行)
        // this.successCallback && this.successCallback(this.value);
        // 当成功回调数组是否大于0,大于0执行成功回调
        while (this.successCallback.length) this.successCallback.shift()(this.value)
    }
    // 定义reject方法,将失败原因传入
    reject = reason => {
        // 如果状态不是等待,则阻止程序向下执行,防止更改promise状态
        if (this.status !== PENDING) return;
        // 将状态更改为失败
        this.status = REJECTED;
        // 保存失败后的原因
        this.reason = reason;
        // 判断失败回调是否存在 如果存在 调用
        // this.failCallback && this.failCallback(this.reason);
        while (this.failCallback.length) this.failCallback.shift()(this.reason)
    }
    /**
     * 成功的回调函数,失败的回调函数
     * then方法返回的是一个promise对象,所以在里面在命名一个promise对象 
     */
    then(successCallback, failCallback) {
        // 参数可选,因为successCallback, failCallback不是必传参数
        successCallback = successCallback ? successCallback : value => value;
        // 参数可选
        failCallback = failCallback ? failCallback : reason => { throw reason };
        // 因为在then方法中需要返回一个promise对象(为了实现then的链式调用),所以在里面在命名一个promise对象 ,其传入的执行器中代码是立即执行的
        let promsie2 = new MyPromise((resolve, reject) => {
            // 判断状态,如果成功者调用成功的回调函数
            if (this.status === FULFILLED) {
                setTimeout(() => {
                    try {
                        // 为了在链式调用中将上一个then中成功回调返回值,传给下一个then中,用x接收返回值
                        let x = successCallback(this.value);
                        /**
                         *  在这里需要判断 x 的值是普通值还是promise对象
                         *  如果是普通值 直接调用下一个promise对象的resolve 
                         *  如果是promise对象 查看promise对象返回的结果 
                         *  再根据promise对象返回的结果 决定调用resolve 还是调用reject
                         *  因此这需要写在公共方法中
                         *  这里为了防止promise对象返回自身报错,需要传入当前promise2,但是这里处在新建promise过程中是获取不到对象的,因此用计时器来解决这个问题
                         */
                        resolvePromise(promsie2, x, resolve, reject)
                    } catch (e) {
                        // 捕获上一个then方法promise中成功回调函数中的执行错误
                        reject(e);
                    }
                }, 0)
            } else if (this.status === REJECTED) {
                // 失败回调
                setTimeout(() => {
                    try {
                        let x = failCallback(this.reason);
                        /**
                         *  判断 x 的值是普通值还是promise对象
                         *  如果是普通值 直接调用下一个promise对象里的resolve 
                         *  如果是promise对象 查看promise对象返回的结果 
                         *  再根据promise对象返回的结果 决定调用resolve 还是调用reject
                         *  这里为了防止promise对象返回自身报错,需要传入当前promise2,但是这里处在新建promise过程中是获取不到对象的,因此用计时器来解决这个问题
                         */
                        resolvePromise(promsie2, x, resolve, reject)
                    } catch (e) {
                        // 捕获上一个then方法promise中失败回调函数中的执行错误,传递给下个then方法中的失败回调函数
                        reject(e);
                    }
                }, 0)
            } else {
                //等待,处理异步请求 将成功回调和失败回调存储起来
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = successCallback(this.value);
                            /**
                             *  判断 x 的值是普通值还是promise对象
                             *  如果是普通值 直接调用下一个promise对象里的resolve 
                             *  如果是promise对象 查看promise对象返回的结果 
                             *  再根据promise对象返回的结果 决定调用resolve 还是调用reject
                             *  这里为了防止promise对象返回自身报错,需要传入当前promise2,但是这里处在新建promise过程中是获取不到对象的,因此用计时器来解决这个问题
                             */
                            resolvePromise(promsie2, x, resolve, reject)
                        } catch (e) {
                            reject(e);
                        }
                    }, 0)
                });
                this.failCallback.push(() => {
                    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)
                });
            }
        });
        return promsie2;
    }
    // 无论成功还是失败都要调用finally中的callback,如果callback有返回值(普通值还是promise),则需要调用promise.resolve将返回值转换为promise
    finally(callback) {
        return this.then(value => {
            // 为了能在then方法后面继续调用then方法需要在callback(callback可能再return一个promise,需要在这个promise执行之后return value);
            return MyPromise.resolve(callback()).then(() => value);
        }, reason => {
            return MyPromise.resolve(callback()).then(() => { throw reason })
        })
    }
    // 处理当前promise失败回调的方法
    catch(failCallback) {
        return this.then(undefined, failCallback)
    }
    // promise中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);
                }
            }
            // 循环判断all方法传入的值是promise对象还是普通值
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                if (current instanceof MyPromise) {
                    // promise 对象,因为有异步操作,需要根据index来判断是否执行完成
                    current.then(value => addData(i, value), reason => reject(reason))
                } else {
                    // 普通值
                    addData(i, array[i]);
                }
            }
        })
    }
    // 只要有一个成功或者失败就返回
	  static race(array) {
	    let promise = new MyPromise((resolve, reject) => {
	      for (let i = 0; i < array.length; i++) {
	        let curr = array[i];
	        // MyPromise实例 结果处理
	        if (curr instanceof MyPromise) {
	          curr.then(resolve, reject);
	        } else {
	          // 非MyPromise实例处理
	          resolve(curr);
	        }
	      }
	    });
	    return promise;
	  }
    static resolve(value) {
        // 判断传入的参数是否是promise对象,是的话直接返回,不是的话创建并返回一个promise对象并将value通过resolve传递出去
        if (value instanceof MyPromise) return value;
        return new MyPromise(resolve => resolve(value));
    }
}

/**
 *
 * 处理then回调函数中返回值
 * @param {*} promsie2
 * @param {*} x 返回值
 * @param {*} resolve  当前promise2对象的resolve
 * @param {*} reject 当前promise2对象的reject
 * @returns
 */
function resolvePromise(promsie2, x, resolve, reject) {
    // 判断处理返回值是否是是当前promise对象
    if (promsie2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    // 判断返回值是否是promise对象
    if (x instanceof MyPromise) {
        // promise 对象
        x.then(value => resolve(value), reason => reject(reason));
    } else {
        // 普通值
        resolve(x);
    }
}

module.exports = MyPromise;

相关文章

最后的控制台返回空数组.控制台在ids.map函数完成之前运行va...
我正在尝试将rxJava与我已经知道的内容联系起来,特别是来自J...
config.jsconstconfig={base_url_api:"https://douban....
我正在阅读MDN中的javascript,并且遇到了这个谈论承诺并且不...
config.jsconstconfig={base_url_api:"https://douban....
这是我的代码main.cpp:#include<string>#include<...