手写Promise.all

92 阅读1分钟

Promise.all


Promise.all方法接收一个数组作为参数,这个参数数组的元素也都是promise实例,该方法返回一个promise示例。

const p = Promise.all([p1, p2, p3]);

p的状态由p1、p2、p3决定,p最后的状态要么是变成fulfilled,要么变成rejected。

  1. 变成fulfilled:只有当p1、p2、p3的状态都变成fulfilled,p的状态才变成fulfilled,这时候p1、p2、p3的返回值组成一个数组,作为参数传递给p的回调函数.
  2. 变成rejected: 只要p1、p2、p3中有一个的状态变成rejected,p的状态就变成rejected,这时候第一个被reject的实例的返回值会作为参数传递给p的回调函数。

实现Promise.all


直接上代码

let PromiseAll = function (proms) {
  return new Promise((resolve, reject) => {
    try {
      const results = []
      let count = 0
      let fulfilledCount = 0
      for (const p of proms) {
        let i = count
        count++
        Promise.resolve(p).then((data) => {
          fulfilledCount++
          results[i] = data
          if (fulfilledCount === count) {
            resolve(results)
          }
        },reject)
      }
      if(count === 0) {
        resolve(results)
      }
    } catch (error) {
      reject(error)
    }
  }
  )
}
PromiseAll([
  Promise.reject(1),
  Promise.resolve(2),
  Promise.resolve(3),
  4,
]).then(
  (data) => {
    // data:[1,2,3,4]
    // 传递[pro1,pro2,pro3,4]的话:内部默认处理Promise.resolve(4)
    console.log("成功", data);
  },
  (reason) => {
    // reason:reason2
    console.log("失败", reason);
  }
);

实现思路:在新建的promise实例内部遍历传递的promise数组(或者是含有迭代器的对象),为了确保输出的结果的顺序和传入的数组元素的顺序一致,需要记录遍历到的promise实例的索引,使用Promise.resolve方法对每个promise实例进行处理,如果遇到错误就直接reject出去,如果正常就将结果添加进结果数组,当成功的次数(fulfilledCount)等于数组长度时就将结果数组resolve出去。