实现Promise.all()

语法

Promise.all(iterable);

参数:

iterable
一个可迭代对象,如 Array 或 String。

返回值:

  • 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promise。
  • 如果传入的参数不包含任何 promise,则返回一个异步完成(asynchronously resolved) Promise。注意:Google Chrome 58 在这种情况下返回一个已完成(already resolved)状态的 Promise。
  • 其它情况下返回一个处理中(pending)的Promise。这个返回的 promise 之后会在所有的 promise 都完成或有一个 promise 失败时异步地变为完成或失败。

说明:

  • 完成(Fulfillment):

如果传入的可迭代对象为空,Promise.all 会同步地返回一个已完成(resolved)状态的promise。

如果所有传入的 promise 都变为完成状态,或者传入的可迭代对象内没有 promise,Promise.all 返回的 promise 异步地变为完成。

在任何情况下,Promise.all 返回的 promise 的完成状态的结果都是一个数组,它包含所有的传入迭代参数对象的值(也包括非 promise 值)。

  • 失败/拒绝(Rejection):

如果传入的 promise 中有一个失败(rejected),Promise.all 异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成。

实现

Promise._all = function (promises) {
  // promises 是可迭代对象,省略参数合法性检查
  return new Promise((resolve, reject) => {
    // Array.from 将可迭代对象转换成数组
    promises = Array.from(promises);
    if (promises.length === 0) {
      resolve([]);
    } else {
      let result = [],
        index = 0;
      for (let i = 0; i < promises.length; i++) {
        // 考虑到i可能是thenable对象也可能是普通值
        Promise.resolve(promises[i]).then(
          (data) => {
            result[i] = data;
            if (++index === promises.length) {
              // 所有的promises状态都是fulfilled,promise.all返回的实例才变成fulfilled态
              resolve(result);
            }
          },
          (err) => {
            reject(err);
            return;
          }
        );
      }
    }
  });
};

Test

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve(2), 1000);
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve(4), 2000);
});

Promise._all([p1, p2]).then((res) => {
  console.log(res); // [2,4]
});

总结

  1. 接收参数是一个promises列表; promises.length === 0,resolve([]);
  2. 返回的是一个promise实例; 所有promise都是resolve,resolve(result);

More

Promise.all()
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all