Promise/A+规范+ECMAScript6的Promsie的扩展api源码实现

什么是Promise?

MDN文档对Promise的解释是: Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。
民间也有一种说法是: Promise是优雅解决异步回调函数嵌套地狱问题的一种解决方案。

下面是我个人对Promise的一个通俗的解释:
Promise/A+规范+ECMAScript6的Promsie的扩展api源码实现_第1张图片

什么是Promise/A+? 它跟ECMAScript 6的Promise又是什么关系?

  • Promise/A+是Promise的一个开放的标准或者是规范,它规范了Promise的术语和要求(包括Promise的三种状态、必须提供一个then方法和Promise的解决流程)。
  • ECMAScript 6里面的Promise是Promise/A+规范的一种实现方案。它是一个规范的具体的一种实现方案,它在原有的Promise/A+规定上扩展了一些API:

Promise.prototype.catch()
Promise.prototype.finally()
Promise.allSettled()
Promise.all()
Promise.race()
Promise.any()
Promise.reject()
Promise.resolve()

下面是用图来形容它们之间的关系


Promise/A+规范+ECMAScript6的Promsie的扩展api源码实现_第2张图片


来看看Promise流程图:

Promise/A+规范+ECMAScript6的Promsie的扩展api源码实现_第3张图片

下面是一个实现了Promsoe/A+规范同时也扩展了ECMAScript6的PromiseAPI的源码并且含有大量注释。(通过了所有promises-aplus-test的测试案例)

Promise/A+规范+ECMAScript6的Promsie的扩展api源码实现_第4张图片

如果你也想测试你自己编写的Promsie是否符合**Promise/A+**规范可以下载一个 “promises-aplus-test” 的工具来测试。下面是安装命令:

	npm install promises-aplus-tests -g

下面是promises-aplus-test的用法:

  Promise.deferred = function() {
     
    const deferred = {
     }
    deferred.promise = new Promise((resolve, reject) => {
     
        deferred.resolve = resolve
        deferred.reject = reject
    })
    return deferred
  }
  module.exports = Promise;

在你编写的promise文件的末尾添加这些代码然后在命令行运行下面命令就可以

	promises-aplus-tests 你要测试的文件名.js
下面是我编写的Promise源码
const PEDDING = "pending",
    FULFILLED = "fulfilled",
    REJECTED = "rejected";
function isPromise(val) {
     
    return (
        val !== undefined &&
        val !== null &&
        (typeof val === 'object' || typeof val === 'function') &&
        typeof val.then === 'function'
    );
}
/**
 * @todo  The Promise Resolution Procedure=>Promise的解决流程
 * @description Promise/A+ 规范
 *  的承诺解决过程是一个抽象的操作作为输入一个承诺和一个值,它表示我们作为[[Resolve]](promise, x)。如果x是可能的,则在行为至少类似于承诺的假设下,
 *  尝试promise采用的状态。否则,它将满足value 。xxpromisex只要对约定的实现公开Promises / A +兼容的then方法,对约定的实现就可以进行互操作。
 *  它还允许Promises / A +实现以合理的then方法“同化”不合格的实现。
    要运行[[Resolve]](promise, x),请执行以下步骤:
    2.3.1    如果promise和x引用相同的对象,promise则以拒绝TypeError为理由。
    2.3.2    如果x是一个承诺,则采用其状态[ 3.4 ]:
      2.3.2.1      如果x未决,则promise必须保持未决状态,直到x实现或被拒绝。
      2.3.2.2      如果/何时x满足,promise则以相同的值满足。
      2.3.2.3      如果/何时x被拒绝,promise则以相同的理由拒绝。
    2.3.3    否则,如果x是对象或函数,
      2.3.3.1     我们then是x.then。[ 3.5 ]
      2.3.3.2     如果检索属性x.then中抛出的异常的结果e,拒绝promise与e作为的原因。
      2.3.3.3     如果then是函数,请使用xas this,第一个参数resolvePromise和第二个参数进行调用rejectPromise,其中:
        2.3.3.3.1      如果/何时resolvePromise使用值调用y,请运行[[Resolve]](promise, y)。
        2.3.3.3.2      如果/当rejectPromise是带一个理由r,拒绝promise与r。
        2.3.3.3.3      如果同时调用resolvePromise和rejectPromise,或者对同一参数进行了多次调用,则第一个调用优先,而所有其他调用均被忽略。
        2.3.3.3.4      如果调用then引发异常e,
        2.3.3..3.4.1       如果resolvePromise或rejectPromise已经被调用,则忽略它。
        2.3.3..3.4.2       否则,拒绝promise与e作为的原因。
      2.3.3.4          如果then不是一个函数,实现promise用x。
    2.3.4     如果x不是一个对象或功能,实现promise与x。
        如果使用参与循环的可循环链的可转换组件来解决承诺,从而[[Resolve]](promise, thenable)最终导致递归性质[[Resolve]](promise, thenable)被再次调用,
    则遵循上述算法将导致无限递归。鼓励但不是必需的实现,以检测这种递归并promise以提供信息TypeError为理由的拒绝。[ 3.6 ]
 * @param {Promise} promise2 
 * @param {*} x 
 * @param {Function} resolve 
 * @param {Function} reject 
 * @returns {void}
 */
function resolvePromise(promise2, x, resolve, reject) {
     
    //如果promise和x引用相同的对象,promise则以拒绝TypeError为理由。
    /**
     * 例子:
     * const p=new Promise((resolve,reject)=>{
     *  resolve(xxx);
     * }).then(v=>{
     *  return p;
     * })
     */
    if (promise2 === x) {
     
        return reject(new TypeError('Chaining cycle detected for promise'));
    }
    //保证promise2的onFulfilled或者onRejected只被调用一次 防止多次调用
    //比如:
    /**
     * new Promise((resolve,reject)=>{
     *    resolve(xxx);
     *    reject(xxx);
     *    resolve(xxx);
     *  });
     * 这样就会导致promise2的onFulfilled或者onRejected被多次调用
     */
    let called = false;
    if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
     
        try {
     
            //then be x.then=>取出then
            const then = x.then;
            // 如果then是函数,就默认是promise了
            if (typeof then === 'function') {
     
                then.call(x,
                    //If/when resolvePromise is called with a value y, run [[Resolve]](promise, y).=> 如果/何时resolvePromise使用值调用y,请运行[[Resolve]](promise, y)。
                    (y) => {
     
                        //只能调用一次
                        if (called) return;
                        called = true;
                        //如果y依旧是一个promise 那么就递归解析
                        /**
                         * 例子:
                         * new Promose((resolve,reject)=>{
                         *     resolve('xxx');
                         * }).then((v)=>{
                         *    return new Promise((resolve,reject)=>{
                         *      setTimeout(()=>{
                         *         resolve(new Promise((resolve,reject)=>{
                         *              resolve(new Promise((resolve,reject)=>{
                         *                  resolve(new Promise(...);//嵌套地狱
                         *              }))
                         *          }))
                         *      }13000)
                         *  })
                         * })
                         */
                        resolvePromise(promise2, y, resolve, reject);
                    },
                    //If/when rejectPromise is called with a reason r, reject promise with r.=>  如果/当rejectPromise是带一个理由r,拒绝promise与r。
                    (r) => {
     
                        //只能调用一次
                        if (called) return;
                        called = true;
                        reject(r);
                    });
            } else {
     
                resolve(x);
            }
        } catch (e) {
     
            //取then失败或者流程报错走到这里
            if (called) return;
            called = true;
            reject(e);
        }
    } else {
     
        //If x is not an object or function, fulfill promise with x.=>如果x不是一个对象或者函数 
        resolve(x);
    }
}
class Promise {
     
    /**
     * @description Promise 构造器主要用于包装不支持promise(返回值不是Promise)的函数。
     * @param {*} executor 
     */
    constructor(executor) {
     
        if (isPromise(executor)) {
     
            // Promise 构造器主要用于包装不支持promise(返回值不是Promise)的函数
            throw new TypeError("Promise resolver # is not a function");
        }
        //私有属性 这里为什么是callbacks(一个事件队列)?请看下面的例子:
        /**
         * const promise=new Promise((resolve,reject)=>{...});
         * promise.then(...);
         * promise.then(...);
         * promise.then(...);
         * promise.then(...);
         * ...可以无穷尽也 
         * 根据promise/A+规范 所有的onFulfilled或者onRejected必须按照原调用顺序执行 所以这里才是一个队列
         */
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];
        this.onFinallyCallbacks = [];
        this.reason = undefined;
        this.value = undefined;
        this.state = PEDDING;
        const reject = (reason) => {
     
            if (this.state === PEDDING) {
     
                this.state = REJECTED;
                //reason=reject(xxx)中传递的xxx
                this.reason = reason;
                this.onRejectedCallbacks.forEach(callback => callback());
                this.onFinallyCallbacks.forEach(callback => callback());
            }
        }
        const resolve = (value) => {
     
            if (this.state === PEDDING) {
     
                this.state = FULFILLED;
                //value=resolve(xxx)中传递的xxx
                this.value = value;
                this.onFulfilledCallbacks.forEach(callback => callback());
                this.onFinallyCallbacks.forEach(callback => callback());
            }
        }
        try {
     
            executor && typeof executor === 'function' && executor(resolve, reject);
        } catch (err) {
     
            reject(err);
        }
    }
    /**
     * @todo  //规范:
    // 当一个 Promise 完成(fulfilled)或者失败(rejected)时,返回函数将被异步调用(由当前的线程循环来调度完成).
       具体的返回值依据以下规则返回。如果 then 中的回调函数:
    // 返回了一个值,那么 then 返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。
    // 没有返回任何值,那么 then 返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined。
    // 抛出一个错误,那么 then 返回的 Promise 将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。
    // 返回一个已经是接受状态的 Promise,那么 then 返回的 Promise 也会成为接受状态,
       并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
    // 返回一个已经是拒绝状态的 Promise,那么 then 返回的 Promise 也会成为拒绝状态,
       并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
    // 返回一个未定状态(pending)的 Promise,那么 then 返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;
       同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。
     * @param {*} onFulfilled  当 Promise 变成接受状态(fulfilled)时调用的函数。该函数有一个参数,即接受的最终结果(the fulfillment  value)。
     *                         如果该参数不是函数,则会在内部被替换为 (x) => x,即原样返回 promise 最终结果的函数
     * @param {*} onRejected   当 Promise 变成拒绝状态(rejected)时调用的函数。该函数有一个参数,即拒绝的原因(rejection reason)。  
     *                         如果该参数不是函数,则会在内部被替换为一个 "Thrower" 函数 (it throws an error it received as argument)。
     * @returns {Promise}
     */
    then(onFulfilled, onRejected) {
     
        if (typeof onFulfilled != 'function') {
     
            //如果该参数不是函数,则会在内部被替换为 (x) => x,即原样返回 promise 最终结果的函数
            onFulfilled = (x) => x;
        }
        if (typeof onRejected != 'function') {
     
            // 如果该参数不是函数,则会在内部被替换为一个 "Thrower" 函数 (it throws an error it received as argument)
            onRejected = (reason) => {
      throw reason };
        }
        //偷懒函数 少写重复代码
        const handler = (promise2, valueOrReason, onFOrR, resolve, reject) => {
     
            try {
     
                const result = onFOrR(valueOrReason);
                resolvePromise(promise2, result, resolve, reject);
            } catch (e) {
     
                reject(e);
            }
        }
        const promise2 = new Promise((resolve, reject) => {
     
            try {
     
                if (this.state === PEDDING) {
     
                    //当前Promise处于pedding状态下 则将onFulfilled和onRejected加入回调队列中 等待Promise的状态被改变时调用
                    this.onFulfilledCallbacks.push(
                        () => {
     
                            //这里为什么用setTimeout? =>2.2.4: `onFulfilled` or `onRejected` must not be called until the execution context stack contains 
                            //only platform code. Clean-stack execution ordering tests (fulfillment case) when the promise is fulfilled asynchronously
                            //timeout of 200ms exceeded. Ensure the done() callback is being called in this test
                            setTimeout(() => {
     
                                /**
                                 *  resolvePromise这个是对 最顶层的Promise嵌套问题
                                 *  这里的处理promise/A+并没有规范,但是ESCMSCript6的Promise扩展了这个功能,所以把es6的扩展也实现一下
                                 *  例子:
                                 *  const new Promose((resolve,reject)=>{
                                 *   resolve(new Promise((resolve,reject)=>{
                                 *       new Promise(...)
                                 *   }))
                                 *  })
                                 */
                                resolvePromise(
                                    promise2,
                                    this.value,
                                    (v) => {
      handler(promise2, v, onFulfilled, resolve, reject); },
                                    (r) => {
      handler(promise2, r, onRejected, resolve, reject); }
                                );
                            }, 0);
                            // setTimeout(() => handler(promise2, this.value, onFulfilled, resolve, reject), 0);
                        }
                    );
                    this.onRejectedCallbacks.push(
                        () => {
     
                            setTimeout(() => handler(promise2, this.reason, onRejected, resolve, reject), 0);
                        }
                    );
                } else if (this.state === FULFILLED) {
     
                    //当前Promise处于fulfilled状态下 则“直接调用” 这里通过setTimeout来执行异步任务
                    setTimeout(() => {
     
                        resolvePromise(
                            promise2,
                            this.value,
                            (v) => {
      handler(promise2, v, onFulfilled, resolve, reject); },
                            (r) => {
      handler(promise2, r, onRejected, resolve, reject); }
                        );
                    }, 0);
                } else if (this.state === REJECTED) {
     
                    //当前Promise处于rejected状态下 则“直接调用” 这里通过setTimeout来执行异步任务 模拟微任务
                    setTimeout(() => handler(promise2, this.reason, onRejected, resolve, reject), 0);
                }
            } catch (err) {
     
                //整个exctutor运行发生异常 则直接reject
                reject(err);
            }
        });
        return promise2;
    }
    /**
     * @todo 规范: catch() 方法返回一个Promise (en-US),并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。
     *             (事实上, calling obj.catch(onRejected)  内部calls obj.then(undefined, onRejected)).
     * 
     * @description                  catch 方法可以用于您的promise组合中的错误处理。
     * @param       {*} onRejected   当Promise 被rejected时,被调用的一个Function。 该函数拥有一个参数:reason    rejection 的原因。
     *                               如果 onRejected 抛出一个错误或返回一个本身失败的 Promise ,  通过 catch() 返回的Promise 被rejected;否则,它将显示为成功(resolved)。
     * @returns {Promise}
     */
    catch (onRejected) {
     
        //事实上, calling obj.catch(onRejected)  内部calls obj.then(undefined, onRejected)
        return this.then(undefined, onRejected);
    }
    /**
     * @todo 规范: finally() 方法返回一个Promise。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。
     *             这为在Promise是否成功完成后都需要执行的代码提供了一种方式。这避免了同样的语句需要在then()和catch()中各写一次的情况。
     * @description 如果你想在 promise 执行完毕后无论其结果怎样都做一些处理或清理时,finally() 方法可能是有用的。
                    finally() 虽然与 .then(onFinally, onFinally) 类似,它们不同的是:
                    调用内联函数时,不需要多次声明该函数或为该函数创建一个变量保存它。
                    由于无法知道promise的最终状态,所以finally的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。
                    与Promise.resolve(2).then(() => {}, () => {}) (resolved的结果为undefined)不同,Promise.resolve(2).finally(() => {}) resolved的结果为 2。
                    同样,Promise.reject(3).then(() => {}, () => {}) (resolved 的结果为undefined), Promise.reject(3).finally(() => {}) rejected 的结果为 3。
                    注意: 在finally回调中 throw(或返回被拒绝的promise)将以 throw() 指定的原因拒绝新的promise.
     * @param {*} onFinally 
     * @returns {Promise}  返回一个设置了 finally 回调函数的Promise对象。 
     */
    finally(onFinally) {
     
        return new Promise((resolve, reject) => {
     
            if (this.state == FULFILLED) {
     
                setTimeout(() => {
     
                    try {
     
                        onFinally();
                        resolve(this.value);
                    } catch (err) {
     
                        reject(err);
                    }
                }, 0);
            } else if (this.state === REJECTED) {
     
                setTimeout(() => {
     
                    try {
     
                        onFinally();
                        resolve(this.reason);
                    } catch (err) {
     
                        reject(err);
                    }
                }, 0);
            } else if (this.state === PEDDING) {
     
                this.onFinallyCallbacks.push(() => {
     
                    try {
     
                        onFinally();
                        resolve(this.state === FULFILLED ? this.value : this.reason);
                    } catch (err) {
     
                        reject(err);
                    }
                });
            }
        });
    }
    /**
     * @static 静态方法
     * @description 规范: Promise.resolve(value)方法返回一个以给定值解析后的Promise 对象。如果这个值是一个 promise,那么将返回这个 promise;
     *              如果这个值是thenable(即带有"then" 方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;
     *              否则返回的promise将以此值完成。此函数将类promise对象的多层嵌套展平。
     * @warning     不要在解析为自身的thenable 上调用Promise.resolve。这将导致无限递归,因为它试图展平无限嵌套的promise。
     * @param {*} value 
     * @returns {Promise}
     */
    static resolve(value) {
     
        return new Promise((resolve, reject) => {
     
            if (isPromise(value)) {
     
                value.then(resolve, reject);
            } else {
     
                resolve(value)
            }
        });
    }
    /**
     * @todo  Promise.reject()方法返回一个带有拒绝原因的Promise对象。
     * @static
     * @description 静态函数Promise.reject返回一个被拒绝的Promise对象。通过使用Error的实例获取错误原因reason对调试和选择性错误捕捉很有帮助。
     * @param {*} reason 
     * @returns {Promise}
     */
    static reject(reason) {
     
        return new Promise((_, reject) => {
     
            reject(reason);
        });
    }
    /**
     * @todo 规范: Promise.all() 方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,
     *       并且只返回一个Promise实例, 那个输入的所有promise的resolve回调的结果是一个数组。这个Promise的resolve回调执行是在
     *       所有输入的promise的resolve回调都结束,或者输入的iterable里没有promise了的时候。它的reject回调执行是,只要任何一个输入的
     *       promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。
     * @description  Promise.allSettled()不管参数中的promise是fulfilled还是rejected,都会等参数中的实例都返回结果,包装实例才会结束。
     *               Promise.all()只有在接受的所有promise实例全部是fulfilled才会走Promise.all([p1,p2,p3]).then()方法,
     *               只要有其中一个promise实例是rejected,就会直接走catch方法,并且catch中只会返回第一个变成rejected的promise的错误
     * @param {*} iterable 
     * @returns {Promise} 规范: 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promise。
                                  如果传入的参数不包含任何 promise,则返回一个异步完成(asynchronously resolved) Promise。
                                  注意:Google Chrome 58 在这种情况下返回一个已完成(already resolved)状态的 Promise。
                                  其它情况下返回一个处理中(pending)的Promise。这个返回的 promise 之后会在所有的 promise 
                                  都完成或有一个 promise 失败时异步地变为完成或失败。 
                                  返回值将会按照参数内的 promise 顺序排列,而不是由调用 promise 的完成顺序决定。
     */
    static all(iterable) {
     
        return new Promise((resolve, reject) => {
     
            try {
     
                let values = [],
                    len = 0, //用来标记已迭代元素的数量 因为iterable可能是用户自定义迭代器对象(没有length或者size属性)。
                    isWalkComplete = false,
                    promiseList = [], //用一个数组保存住按照iterable中的排序的所有promise对象
                    promise;
                const getSortPromiseValue = () => promiseList.map(p => p.value);
                for (const iter of iterable) {
     
                    promise = !isPromise(iter) ? /***传入的参数里面不是promise,将它转变成promise***/ Promise.resolve(iter) : iter;
                    promiseList.push(promise); //复制或者说保存当前顺序的promise的引用
                    //执行then方法
                    promise.then(
                        (v) => {
     
                            values.push(v);
                            if (
                                typeof iterable === 'string' ||
                                Array.isArray(iterable) ||
                                iterable instanceof Map ||
                                iterable instanceof Set
                            ) {
     
                                if (values.length === (iterable.length || iterable.size)) {
     
                                    //处理返回值的顺序
                                    values = getSortPromiseValue();
                                    resolve(values);
                                }
                            } else if (isWalkComplete && values.length === len) {
     
                                //处理返回值的顺序
                                values = getSortPromiseValue();
                                resolve(values)
                            }
                        },
                        reason => reject(reason) //传入第一个发生reject的reason
                    ); //then end
                    len++;
                } //end for
                isWalkComplete = true;
            } catch (err) {
     
                reject(err);
            }
        });
    }
    /**
     * @todo 该Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,
     *       并带有一个对象数组,每个对象表示对应的promise结果。
             当您有多个彼此不依赖的异步任务成功完成时,或者您总是想知道每个promise的结果时,通常使用它。
             相比之下,Promise.all() 更适合彼此相互依赖或者在其中任何一个reject时立即结束
     * @param {*} iterable 一个可迭代的对象,例如Array,其中每个成员都是Promise。
     * @returns {Promise}  一旦所指定的 promises 集合中每一个 promise 已经完成,无论是成功的达成或被拒绝,未决议的 Promise将被异步完成。
     *                     那时,所返回的 promise 的处理器将传入一个数组作为输入,该数组包含原始 promises 集中每个 promise 的结果。
                           对于每个结果对象,都有一个 status 字符串。如果它的值为 fulfilled,则结果对象上存在一个 value 。如果值为 rejected,
                           则存在一个 reason 。value(或 reason )反映了每个 promise 决议(或拒绝)的值。
     */
    static allSettled(iterable) {
     
        return new Promise((resolve, reject) => {
     
            //已经完成了的Promose 不管是状态是fulfilled还是rejected
            let completePromiseList = [],
                promiseList = [],
                len = 0,
                completePromiseCount = 0,
                isWalkComplete = false;
            const getSortPromiseStatus = () => {
     
                return promiseList.map(p => {
     
                    return {
     
                        status: p.state,
                        [p.state === FULFILLED ? 'value' : 'reason']: p.state === FULFILLED ? p.value : p.reason
                    }
                });
            };
            for (const x of iterable) {
     
                let promise = !isPromise(x) ? Promise.resolve(x) : x;
                promiseList.push(promise);
                promise.finally(() => {
     
                    completePromiseCount++;
                    if (isWalkComplete && completePromiseCount === len) {
     
                        completePromiseList = getSortPromiseStatus();
                        resolve(completePromiseList);
                    }
                });
                len++;
            }
            isWalkComplete = true;
        });
    }
    /**
     * @todo Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
     * @description race 函数返回一个 Promise,它将与第一个传递的 promise 相同的完成方式被完成。
     *              它可以是完成( resolves),也可以是失败(rejects),这要取决于第一个完成的方式是两个中的哪个。
                    如果传的迭代是空的,则返回的 promise 将永远等待。
                    如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,则 Promise.race 将解析为迭代中找到的第一个值。
     * @param {*} iterable 可迭代对象,类似Array。详见 iterable。
     * @returns {Promise} 一个待定的 Promise 只要给定的迭代中的一个promise解决或拒绝,就采用第一个promise的值作为它的值,
     *                    从而异步地解析或拒绝(一旦堆栈为空)。
     */
    static race(iterable) {
     
        return new Promise((resolve, reject) => {
     
            for (const iter of iterable) {
     
                //如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,则 Promise.race 将解析为迭代中找到的第一个值。
                if (isPromise(iter)) {
     
                    //如果iter是个promise
                    const promise = iter;
                    //判断promise的状态来动态选择接受或者拒绝
                    if (promise.state === FULFILLED) {
     
                        promise.then(resolve);
                    } else if (promise.state === REJECTED) {
     
                        promise.then(undefined, reject);
                    } else if (promise.state === PEDDING) {
     
                        promise.then(resolve, reject);
                    }
                } else {
     
                    //非promise类型直接resolve
                    resolve(iter)
                }
            }
        });
    }
    /**
     * @todo ECMAScript6的文档规范: Promise.any() 接收一个Promise可迭代对象,只要其中的一个 promise 成功,就返回那个已经成功的 promise 。
     *       如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise 和AggregateError类型的实例,
     *       它是 Error 的一个子类,用于把单一的错误集合在一起。本质上,这个方法和Promise.all()是相反的。
     * @description 这个方法用于返回第一个成功的 promise 。只要有一个 promise 成功此方法就会终止,它不会等待其他的 promise 全部完成。
                    不像 Promise.all() 会返回一组完成值那样(resolved values),我们只能得到一个成功值(假设至少有一个 promise 完成)。
                    当我们只需要一个 promise 成功,而不关心是哪一个成功时此方法很有用的。
                    同时, 也不像 Promise.race() 总是返回第一个结果值(resolved/reject)那样,这个方法返回的是第一个 成功的 值。
                    这个方法将会忽略掉所有被拒绝的 promise,直到第一个 promise 成功。
     * @warning Promise.any() 方法依然是实验性的,尚未被所有的浏览器完全支持。它当前处于 TC39 第四阶段草案(Stage 4)
     * @param {*} iterable  一个可迭代的对象, 例如 Array、Set、Map、String
     * @returns {Promise}  如果传入的参数是一个空的可迭代对象,则返回一个 已失败(already rejected) 状态的 Promise。
                           如果传入的参数不包含任何 promise,则返回一个 异步完成 (asynchronously resolved)的 Promise。
                           其他情况下都会返回一个处理中(pending) 的 Promise。 只要传入的迭代对象中的任何一个 promise 变成成功(resolve)
                           状态,或者其中的所有的 promises 都失败,那么返回的 promise 就会 异步地(当调用栈为空时) 
                           变成成功/失败(resolved/reject)状态。
     */
    static any(iterable) {
     
        return new Promise((resolve, reject) => {
     
            let len = 0, //记录迭代器中元素的数量
                isWalkComplete = false, //标识迭代器遍历完成
                promiseList = [], //用一个数组保存住按照iterable中的排序的所有promise对象
                errors = []; //记录所有的错误
            const getSortPromiseReason = () => promiseList.map(p => p.reason);
            for (const iter of iterable) {
     
                if (isPromise(iter)) {
     
                    const promise = iter;
                    promiseList.push(promise);
                    promise.then(
                        v => {
     
                            resolve(v);
                            return;
                        },
                        reason => {
     
                            errors.push(reason);
                            //迭代器遍历完成 但是所有的promise值都失败了
                            if (isWalkComplete && errors.length === len) {
     
                                //获取排序后的promise的reason
                                errors = getSortPromiseReason();
                                reject(new AggregateError(errors, 'All promises were rejected'));
                            }
                        }
                    );
                } else {
     
                    resolve(iter);
                }
                len++;
            }
            isWalkComplete = true;
            //判断迭代器是否为空
            if (len === 0) {
     
                reject(new AggregateError(errors, 'All promises were rejected'));
            }
        });
    }
}


你可能感兴趣的:(javascript)