Собственный es6 инкапсулирует объект Promise

GitHub ECMAScript 6

Примечания к выпуску

  • Время обновления: 23 января 2019 г.

Я сделал выполнение тогдашнего метода синхронным, что не соответствует спецификации.

В ["Promises/A+ Specification"][6] в подразделе [Then Method] [Call Timing] говорится: "onFulfilled и onRejected могут быть вызваны только тогда, когда стек среды выполнения содержит только код платформы", вот особый вид в Комментарий.

Поэтому я будуonFulfilledа такжеonRejectedКод находится в "thenВыполняется в новом стеке выполнения после цикла событий, в котором был вызван метод, черезsetTimeoutМетод помещает задачу в конец текущего раунда очереди задач. Код добавлен в последнюю часть - шаг девятый.

Что касается механизма работы очереди задач, если вам интересно, вы можете прочитать работу г-на Жуана Ифэна.«Подробное объяснение механизма выполнения JavaScript: снова поговорим о цикле событий»


Функция реализации:

  • осуществленныйPromiseБазовые функции, как и нативные, подходят для асинхронных и синхронных операций, в том числе:
    • MyPromise.prototype.then()
    • MyPromise.prototype.catch()с роднымPromiseнемного отличается
    • MyPromise.prototype.finally()
    • MyPromise.all()
    • MyPromise.race()
    • MyPromise.resolve()
    • MyPromise.reject()
  • rejectedТакже был решен процесс всплытия состояния: если отклонение текущего промиса не захвачено, оно будет всплывать до конца, пока не будет поймано
  • MyPromiseПосле того, как состояние изменилось, его нельзя изменить снова

Недостатки:

  • Когда ошибка кода перехватывается уловом, информация о подсказке (захваченный объект ошибки) больше, чем нативный промис.
  • Код написан на es6, и будет считаться написанным на es5, чтобы его можно было применять к проектам es5; если он написан на es5, стрелочные функции не используются, и эту проблему необходимо учитывать

тестовое задание:index.html

  • На этой странице 27 тестовых примеров, которые проверяют каждую функцию, каждый метод и некоторые специальные тесты, могут быть какие-то упущения, можете поиграть, если интересно;
  • Визуальная работа удобна для тестирования, каждый раз при запуске примера вы можете видеть результаты при открытии отладочной консоли, рекомендуется открывать ее одновременно.index.jsИграйте, наблюдая за кодом;
  • Тот же набор кода, вышеMyPromiseРезультат операции, ниже оригиналPromiseрезультат операции;

награда

  • Этот процесс очень радует, я могу сам бросить вызов оригинальным вещам, это мой первый раз;
  • Провел много дней, бросаяPromiseСначала поймите его, затем подумайте о нем и, наконец, шаг за шагом осознайте его функцию, и его понимание будет продолжать углубляться и становиться все более и более полным;
  • При написании новой функции обнаруживается, что в этой новой функции отсутствует предыдущая функция, в это время необходимо понять взаимосвязь между ними и переосмыслить предыдущую функцию, в этом повторении несомненно углубился слой понимания;
  • then/catchМетод самый трудный, постоянно возиться;
  • Наконец, после того, как все функции были реализованы, я вспомнил ключевой момент «После того, как состояние промиса определено, его нельзя изменить», и была добавлена ​​некоторая логика для его решения. Поэтому этот процесс трудно защитить от утечек, и, возможно, в текущем коде все еще есть какие-то скрытые проблемы, которые не были обнаружены.
  • rejectВсплывание состояния — сложная проблема, но я специально не упомянул об этом в следующем коде, и у меня нет возможности прояснить это.

код

Вставьте код ниже, включая весь мыслительный процесс, это будет немного долго
Чтобы написать логику спецификации, я использую следующие комментарии для обозначения, и все изменение кода только отмечает начало этой кучи.
//++- добавлен код
//-+- модифицированный код

Первым шагом является определение класса MyPromise.

Вы можете выбрать любое имя, мое — MyPromise, которое не заменяет оригинальный Promise.

  • Конструктор передает функцию обратного вызоваcallback. когда новыйMyPromiseобъект, нам нужно запустить этот обратный вызов, иcallbackОн также имеет два параметра, которыеresolveа такжеreject, они также представлены в виде функций обратного вызова;
  • Несколько переменных определены для сохранения некоторых текущих результатов и статусов, очередей событий, см. примечания;
  • выполнить функциюcallbackкогда, еслиresolveсостояние, сохраните результат вthis.__succ_res, статус помечается как успешный, еслиrejectстатус, операция аналогична;
  • Также определяет наиболее часто используемыеthenметод, являющийся методом-прототипом;
  • воплощать в жизньthenметод, определить, является ли состояние объекта успешным или неудачным, выполнить соответствующий обратный вызов соответственно и передать результат в обработку обратного вызова;
  • получить здесь...argи входящие параметры...this.__succ_resОба используют оператор распространения, чтобы иметь дело с несколькими параметрами, он передается вthenобратный вызов метода.

callbackОбратный вызов использует здесь функции стрелок,thisуказывает на текущийMyPromiseобъект, поэтому нет необходимости иметь дело сthisвопрос.

class MyPromise {
    constructor(callback) {
        this.__succ_res = null;     //保存成功的返回结果
        this.__err_res = null;      //保存失败的返回结果
        this.status = 'pending';    //标记处理的状态
        //箭头函数绑定了this,如果使用es5写法,需要定义一个替代的this
        callback((...arg) => {
            this.__succ_res = arg;
            this.status = 'success';
        }, (...arg) => {
            this.__err_res = arg;
            this.status = 'error';
        });
    }
    then(onFulfilled, onRejected) {
        if (this.status === 'success') {
            onFulfilled(...this.__succ_res);
        } else if (this.status === 'error') {
            onRejected(...this.__err_res);
        };
    }
};

сюда,MyPromiseВы можете просто реализовать некоторый синхронный код, например:

new MyPromise((resolve, reject) => {
    resolve(1);
}).then(res => {
    console.log(res);
});
//结果 1

Второй шаг — добавить асинхронную обработку

При выполнении асинхронного кодаthenМетод будет выполнен до асинхронного результата, и результат не может быть получен из вышеуказанной обработки.

  • Во-первых, поскольку он асинхронный,thenметод вpendingвыполняется, поэтому добавьтеelse;
  • воплощать в жизньelseКогда у нас еще нет результата, мы можем только поместить обратный вызов, который необходимо выполнить, в очередь и выполнить его, когда это необходимо, поэтому определяется новая переменная.this.__queueсохранить очередь событий;
  • Когда выполняется асинхронный код, на этот разthis.__queueВсе обратные вызовы в очереди выполняются один раз, если этоresolveстатус, выполните соответствующийresolveкод.
class MyPromise {
    constructor(fn) {
        this.__succ_res = null;     //保存成功的返回结果
        this.__err_res = null;      //保存失败的返回结果
        this.status = 'pending';    //标记处理的状态
        this.__queue = [];          //事件队列		//++
        //箭头函数绑定了this,如果使用es5写法,需要定义一个替代的this
        fn((...arg) => {
            this.__succ_res = arg;
            this.status = 'success';
            this.__queue.forEach(json => {			//++
               json.resolve(...arg);
            });
        }, (...arg) => {
            this.__err_res = arg;
            this.status = 'error';
            this.__queue.forEach(json => {			//++
                json.reject(...arg);
            });
        });
    }
    then(onFulfilled, onRejected) {
        if (this.status === 'success') {
            onFulfilled(...this.__succ_res);
        } else if (this.status === 'error') {
            onRejected(...this.__err_res);
        } else {										//++
            this.__queue.push({resolve: onFulfilled, reject: onRejected});
        };
    }
};

В этот момент,MyPromiseУже можно реализовать какой-нибудь простой асинхронный код. прецедентindex.html, эти два примера уже могут быть реализованы.

  • 1 异步测试--resolve
  • 2 异步测试--reject

Третий шаг, присоединяйтесь к цепочке вызовов

На самом деле, роднойPromiseМетод then объекта возвращаетPromiseобъект, новыйPromiseобъект, чтобы всегда поддерживать связанные вызовыthenопускаться. . . а также,thenметод может получить предыдущийthenМетод обрабатывает результат возврата. согласно сPromiseХарактеристический анализ этого возвращаемого результата имеет 3 возможности:

  1. MyPromiseобъект;
  2. имеютthenобъект метода;
  3. другие значения. Эти три случая рассматриваются отдельно.
  • Первое, о чем идет речь, это,thenметод возвращаетMyPromiseобъект, функция обратного вызова которого получаетresFnа такжеrejFnДве функции обратного вызова;
  • Инкапсулируйте код обработки успешного состояния какhandleФункция, которая принимает успешный результат в качестве параметра;
  • handleВ функции, согласноonFulfilledРазные возвращаемые значения, разная обработка:
    • Во-первых, получитьonFulfilledвозвращаемое значение (если есть), сохраненное какreturnVal;
    • Затем, судитеreturnValСуществует ли тогда метод, который включает случаи 1 и 2, рассмотренные выше (этоMyPromiseобъект или имеетthenдругие объекты метода), для нас все равно;
    • После этого, если естьthenметод, немедленно вызовите егоthenметод, перебрасывая результаты успеха и неудачи на новыйMyPromiseФункция обратного вызова объекта, если нет, то результат передается вresFnПерезвоните.
class MyPromise {
    constructor(fn) {
        this.__succ_res = null;     //保存成功的返回结果
        this.__err_res = null;      //保存失败的返回结果
        this.status = 'pending';    //标记处理的状态
        this.__queue = [];          //事件队列
        //箭头函数绑定了this,如果使用es5写法,需要定义一个替代的this
        fn((...arg) => {
            this.__succ_res = arg;
            this.status = 'success';
            this.__queue.forEach(json => {
                json.resolve(...arg);
            });
        }, (...arg) => {
            this.__err_res = arg;
            this.status = 'error';
            this.__queue.forEach(json => {
                json.reject(...arg);
            });
        });
    }
    then(onFulfilled, onRejected) {
        return new MyPromise((resFn, rejFn) => {							//++
            if (this.status === 'success') {
               handle(...this.__succ_res);								//-+
            } else if (this.status === 'error') {
                onRejected(...this.__err_res);
            } else {
               this.__queue.push({resolve: handle, reject: onRejected});        //-+
            };
            function handle(value) {									//++
                //then方法的onFulfilled有return时,使用return的值,没有则使用保存的值
                let returnVal = onFulfilled instanceof Function && onFulfilled(value) || value;
                //如果onFulfilled返回的是新MyPromise对象或具有then方法对象,则调用它的then方法
                if (returnVal && returnVal['then'] instanceof Function) {
                    returnVal.then(res => {
                        resFn(res);
                    }, err => {
                        rejFn(err);
                    });
                } else {//其他值
                    resFn(returnVal);
                };
            };
        })
    }
};

сюда,MyPromiseОбъект уже поддерживает связанные вызовы, тестовый пример:4 链式调用--resolve. Но, очевидно, мы еще не закончилиrejectСвязанные вызовы в состояние.
Идея обработки аналогична, в определенииerrBackфункция, проверкаonRejectedСодержит ли возвращаемый результатthenметоды, о которых идет речь отдельно. Стоит отметить, что если возвращаемое значение является нормальным значением, его следует вызыватьresFn, вместоrejFn, потому что это возвращаемое значение принадлежит новомуMyPromiseобъект, состояние которого не зависит от текущегоMyPromiseОпределяется состояние объекта. То есть возвращается обычное значение, не указанноеrejectсостояние, мы по умолчаниюresolveусловие.

Код слишком длинный, только показать часть изменений.

then(onFulfilled, onRejected) {
    return new MyPromise((resFn, rejFn) => {
        if (this.status === 'success') {
            handle(...this.__succ_res);
        } else if (this.status === 'error') {
           errBack(...this.__err_res);									//-+
        } else {
           this.__queue.push({resolve: handle, reject: errBack});			//-+
        };
        function handle(value) {
            //then方法的onFulfilled有return时,使用return的值,没有则使用保存的值
            let returnVal = onFulfilled instanceof Function && onFulfilled(value) || value;
            //如果onFulfilled返回的是新MyPromise对象或具有then方法对象,则调用它的then方法
            if (returnVal && returnVal['then'] instanceof Function) {
                returnVal.then(res => {
                    resFn(res);
                }, err => {
                    rejFn(err);
                });
            } else {//其他值
                resFn(returnVal);
            };
        };
        function errBack(reason) {										//++
	        if (onRejected instanceof Function) {
	        	//如果有onRejected回调,执行一遍
	            let returnVal = onRejected(reason);
	            //执行onRejected回调有返回,判断是否thenable对象
	            if (typeof returnVal !== 'undefined' && returnVal['then'] instanceof Function) {
	                returnVal.then(res => {
	                    resFn(res);
	                }, err => {
	                    rejFn(err);
	                });
	            } else {
	                //无返回或者不是thenable的,直接丢给新对象resFn回调
	                resFn(returnVal);				//resFn,而不是rejFn
	            };
	        } else {//传给下一个reject回调
	            rejFn(reason);
	        };
        };
    })
}

Сейчас,MyPromiseОбъекты уже хорошо поддерживают цепочку вызовов, тестовый пример:

  • 4 链式调用--resolve
  • 5 链式调用--reject
  • 28 then回调返回Promise对象(reject)
  • 29 then方法reject回调返回Promise对象

Четвертый шаг, реализация методов MyPromise.resolve() и MyPromise.reject()

потому что другие методыMyPromise.resolve()Метод имеет зависимости, поэтому сначала реализуйте этот метод. сначала полностью понятьMyPromise.resolve()Особенности метода, изученного учителем Жуань Ифэном.Начало работы с ECMAScript 6дляMyPromise.resolve()В части описания метода известно, что функция этого метода очень проста, которая заключается в преобразовании параметра вMyPromiseОбъект, ключевой момент кроется в форме параметров, а именно:

  • параметр являетсяMyPromiseпример;
  • параметр являетсяthenableобъект;
  • параметр не имеетthenобъект метода или вообще не объект;
  • без всяких параметров.

Идея обработки такова:

  • Сначала рассмотрим крайние случаи, когда параметр не определен или равен нулю, и непосредственно обработаем передачу исходного значения;
  • Во-вторых, параметрыMyPromiseнапример, никакой обработки не требуется;
  • Тогда параметры другиеthenableобъект, назовите егоthenметод, передавая соответствующее значение новомуMyPromiseобратный вызов объекта;
  • Наконец, это обработка обычных значений.

MyPromise.reject()Метод относительно прост. а такжеMyPromise.resolve()разные методы,MyPromise.reject()Параметры метода будут переданы как естьrejectПричина становится параметром последующего метода.

MyPromise.resolve = (arg) => {
    if (typeof arg === 'undefined' || arg == null) {//无参数/null
        return new MyPromise((resolve) => {
            resolve(arg);
        });
    } else if (arg instanceof MyPromise) {
        return arg;
    } else if (arg['then'] instanceof Function) {
        return new MyPromise((resolve, reject) => {
            arg.then((res) => {
                resolve(res);
            }, err => {
                reject(err);
            });
        });
    } else {
        return new MyPromise(resolve => {
            resolve(arg);
        });
    }
};
MyPromise.reject = (arg) => {
    return new MyPromise((resolve, reject) => {
        reject(arg);
    });
};

Есть 8 тестовых случаев:18-25, вы можете играть, если вам интересно.

Пятый шаг, реализация методов MyPromise.all() и MyPromise.race()

MyPromise.all()метод получает кучуMyPromiseОбъекты, обратный вызов выполнен только тогда, когда они оба успешны. полагатьсяMyPromise.resolve()метод поставить неMyPromiseПараметры преобразуются вMyPromiseобъект.
каждый объект выполняетthenметод, сохранить результаты в массиве, когда они все будут выполнены, то естьi === arr.length, перед вызовомresolve()Обратный вызов, передача результата.
MyPromise.race()Метод также аналогичен, разница в том, что здесь делаетсяdoneФлаги, если один из них изменит состояние, другие изменения приниматься не будут.

MyPromise.all = (arr) => {
    if (!Array.isArray(arr)) {
        throw new TypeError('参数应该是一个数组!');
    };
    return new MyPromise(function(resolve, reject) {
        let i = 0, result = [];
        next();
        function next() {
            //如果不是MyPromise对象,需要转换
            MyPromise.resolve(arr[i]).then(res => {
                result.push(res);
                i++;
                if (i === arr.length) {
                    resolve(result);
                } else {
                    next();
                };
            }, reject);
        };
    })
};
MyPromise.race = arr => {
    if (!Array.isArray(arr)) {
        throw new TypeError('参数应该是一个数组!');
    };
    return new MyPromise((resolve, reject) => {
        let done = false;
        arr.forEach(item => {
            //如果不是MyPromise对象,需要转换
            MyPromise.resolve(item).then(res => {
                if (!done) {
                    resolve(res);
                    done = true;
                };
            }, err => {
                if (!done) {
                    reject(err);
                    done = true;
                };
            });
        })
    })

}

Прецедент:

  • 6 all方法
  • 26 race方法测试

Шестой шаг, реализация методов Promise.prototype.catch() и Promise.prototype.finally()

Они по существуthenРасширение метода, обработка особых случаев.
Часть комментария в коде catch — это мое оригинальное решение: при запуске catch, если он уже находится в состоянии ошибки, запустить обратный вызов напрямую; если он находится в других состояниях, поместите функцию обратного вызова в очередь событий и выполните ее, когда предыдущее состояние отклонения, наконец, получено; поскольку catch напрямую получает состояние отклонения, разрешение в очереди является пустой функцией, чтобы предотвратить сообщение об ошибке.
Я смотрел это позжеСправочная статья 3Я понял, что есть лучший способ написать это, поэтому я заменил его.

class MyPromise {
	constructor(fn) {
		//...略
	}
    then(onFulfilled, onRejected) {
    	//...略
	}
    catch(errHandler) {
        // if (this.status === 'error') {
        //     errHandler(...this.__err_res);
        // } else {
        //     this.__queue.push({resolve: () => {}, reject: errHandler});
        //     //处理最后一个Promise的时候,队列resolve推入一个空函数,不造成影响,不会报错----如果没有,则会报错
        // };
        return this.then(undefined, errHandler);
    }
    finally(finalHandler) {
        return this.then(finalHandler, finalHandler);
    }
};

Прецедент:

  • 7 catch测试
  • 16 finally测试——异步代码错误
  • 17 finally测试——同步代码错误

Шаг седьмой, захват ошибок кода

В настоящее время нашcatchУ него пока нет возможности отлавливать ошибки кода. Подумайте, откуда берется неправильный код? Это должен быть код пользователя. Два источника:

  • MyPromiseобратный вызов конструктора объекта
  • then2 обратных вызова для метода Способ обнаружения ошибок запуска кода является роднымtry...catch..., поэтому я использую его, чтобы обернуть эти обратные вызовы для запуска и соответствующим образом обработать обнаруженные ошибки.

Для обеспечения ясности кода извлекаютсяresolver,rejecterДве функции, т.к. они написаны на es5, нужно обрабатывать вручнуюthisуказать на проблему

class MyPromise {
    constructor(fn) {
        this.__succ_res = null;     //保存成功的返回结果
        this.__err_res = null;      //保存失败的返回结果
        this.status = 'pending';    //标记处理的状态
        this.__queue = [];          //事件队列
        //定义function需要手动处理this指向问题
        let _this = this;									//++
        function resolver(...arg) {							//++
            _this.__succ_res = arg;
            _this.status = 'success';
            _this.__queue.forEach(json => {
                json.resolve(...arg);
            });
        };
        function rejecter(...arg) {							//++
	        _this.__err_res = arg;
	        _this.status = 'error';
	        _this.__queue.forEach(json => {
	            json.reject(...arg);
	        });
        };
        try {												//++
       		fn(resolver, rejecter);							//-+
        } catch(err) {										//++
            this.__err_res = [err];
            this.status = 'error';
            this.__queue.forEach(json => {
                json.reject(...err);
            });
        };
    }
    then(onFulfilled, onRejected) {
        //箭头函数绑定了this,如果使用es5写法,需要定义一个替代的this
        return new MyPromise((resFn, rejFn) => {
            function handle(value) {
                //then方法的onFulfilled有return时,使用return的值,没有则使用回调函数resolve的值
                let returnVal = value;						//-+
                if (onFulfilled instanceof Function) {		//-+
                    try {									//++
                        returnVal = onFulfilled(value);
                    } catch(err) {							//++
                        //代码错误处理
                        rejFn(err);
                        return;
                    }
                };
                if (returnVal && returnVal['then'] instanceof Function) {
                	//如果onFulfilled返回的是新Promise对象,则调用它的then方法
                    returnVal.then(res => {
                        resFn(res);
                    }, err => {
                        rejFn(err);
                    });
                } else {
                    resFn(returnVal);
                };
            };
            function errBack(reason) {
                //如果有onRejected回调,执行一遍
                if (onRejected instanceof Function) {
                    try {													//++
                        let returnVal = onRejected(reason);
                        //执行onRejected回调有返回,判断是否thenable对象
                        if (typeof returnVal !== 'undefined' && returnVal['then'] instanceof Function) {
                            returnVal.then(res => {
                                resFn(res);
                            }, err => {
                                rejFn(err);
                            });
                        } else {
                            //不是thenable的,直接丢给新对象resFn回调
                            resFn(returnVal);
                        };
                    } catch(err) {											//++
                        //代码错误处理
                        rejFn(err);
                        return;
                    }
                } else {//传给下一个reject回调
                    rejFn(reason);
                };
            };
            if (this.status === 'success') {
                handle(...this.__succ_res);
            } else if (this.status === 'error') {
                errBack(...this.__err_res);
            } else {
                this.__queue.push({resolve: handle, reject: errBack});
            };
        })
    }
};

Прецедент:

  • 11 catch测试——代码错误捕获
  • 12 catch测试——代码错误捕获(异步)
  • 13 catch测试——then回调代码错误捕获
  • 14 catch测试——代码错误catch捕获

Среди них 12-й тест на ошибку асинхронного кода, результат показывает, что об ошибке сообщается напрямую, ошибка не обнаруживается, собственныйPromiseТоже самое, я как-то не понимаю, почему его не захватывают, чтобы обращаться с ним.

在这里插入图片描述

Восьмой шаг: обработайте состояние MyPromise, чтобы определить, что его нельзя изменить снова.

ЭтоPromiseОдной из ключевых особенностей , с которой несложно справиться, добавление оценки состояния при выполнении обратного вызова, если он уже находится в состоянии успеха или сбоя, код обратного вызова не будет запущен.

class MyPromise {
    constructor(fn) {
        this.__succ_res = null;     //保存成功的返回结果
        this.__err_res = null;      //保存失败的返回结果
        this.status = 'pending';    //标记处理的状态
        this.__queue = [];          //事件队列
        //箭头函数绑定了this,如果使用es5写法,需要定义一个替代的this
        let _this = this;
        function resolver(...arg) {
            if (_this.status === 'pending') {				//++
                //如果状态已经改变,不再执行本代码
                _this.__succ_res = arg;
                _this.status = 'success';
                _this.__queue.forEach(json => {
                    json.resolve(...arg);
                });
            };
        };
        function rejecter(...arg) {
            if (_this.status === 'pending') {				//++
                //如果状态已经改变,不再执行本代码
                _this.__err_res = arg;
                _this.status = 'error';
                _this.__queue.forEach(json => {
                    json.reject(...arg);
                });
            };
        };
        try {
            fn(resolver, rejecter);
        } catch(err) {
            this.__err_res = [err];
            this.status = 'error';
            this.__queue.forEach(json => {
                json.reject(...err);
            });
        };
    }
    //...略
};

Прецедент:

  • 27 Promise状态多次改变

Девятый шаг, методы onFulfilled и onRejected выполняются асинхронно.

До сих пор, если выполняется следующий код,

function test30() {
  function fn30(resolve, reject) {
      console.log('running fn30');
      resolve('resolve @fn30')
  };
  console.log('start');
  let p = new MyPromise(fn30);
  p.then(res => {
      console.log(res);
  }).catch(err => {
      console.log('err=', err);
  });
  console.log('end');
};

Результат:

//MyPromise结果
// start
// running fn30
// resolve @fn30
// end

//原生Promise结果:
// start
// running fn30
// end
// resolve @fn30

Два результата отличаются, потому что методы onFulfilled и onRejected не выполняются асинхронно, и необходимо выполнить следующую обработку, а их коды помещаются в конец текущего раунда очередей задач для выполнения.

function MyPromise(callback) {
    //略……

    var _this = this;
    function resolver(res) {
        setTimeout(() => {      //++ 利用setTimeout调整任务执行队列
            if (_this.status === PENDING) {
                _this.status = FULFILLED;
                _this.__succ__res = res;
                _this.__queue.forEach(item => {
                    item.resolve(res);
                });
            };            
        }, 0);
    };
    function rejecter(rej) {
        setTimeout(() => {      //++
            if (_this.status === PENDING) {
                _this.status = REJECTED;
                _this.__err__res = rej;
                _this.__queue.forEach(item => {
                    item.reject(rej);
                });
            };            
        }, 0);
    };
    
    //略……
};

Прецедент:

  • 30 then方法的异步执行

Выше приведены все мои идеи и процессы написания кода. Полный код и тестовый код дляgithubскачать


Справочная статья