手写 Promise.all

42 阅读1分钟

Promise.all() 返回一个新的 Promise 对象,该对象在所有传入的 Promise 对象都已解决时才会被解决,并且该对象的解决值是一个数组,包含所有传入 Promise 对象的解决值,这些值的顺序与传入的 Promise 对象的顺序相同。

有以下几个注意点

  • 写在 Promise 上,而不是原型上
  • 入参是Promise对象组成的可迭代对象(通常是数组),返回 promise 对象
  • 使用数组记录结果,注意不能直接 push
  • 计数器与数组长度一致时,说明都 resolve
  • 只要有一个 reject 就整体 reject
  • 如果传入 Promise.all() 的可迭代对象为空,则返回的 Promise 对象会立即解决,并且解决值为一个空数组([]
  • 需要将 list 非 promise 项转化
Promise.myAll = (list) => {
  let results = [] // 存放结果
  let count = 0 // 计数器
  return new Promise((resolve, reject) => {
    if (list.length === 0) {
      resolve([])
    }
    list.map((promise, index) => {
      Promise.resolve(promise).then((res) => {
        // 结果与传入的 promise 顺序保持一致,不能直接 push
        results[index] = res
        count++
        if (count >= list.length) {
          resolve(results)
        }
      }, (err) => {
        reject(err)
      })
    })
  })
}

以下是测试代码

const p1 = Promise.resolve(1)
const p2 = new Promise((resolve) => {
  setTimeout(() => resolve(2), 1000)
})
const p3 = new Promise((resolve) => {
  setTimeout(() => resolve(3), 3000)
})
const notPromise = 'notPromise'

const p4 = Promise.reject('err4')
const p5 = Promise.reject('err5')
// 1. 所有的Promise都成功了
const p11 = Promise.myAll([p1, p3, p2, notPromise])
  .then(console.log) // [1, 3, 2, 'notPromise']
  .catch(console.log)

// 2. 有一个Promise失败了
const p12 = Promise.myAll([p1, p2, p4])
  .then((res) => console.log(res))
  .catch((err) => console.log(err)) // err4

// 3. 有两个Promise失败了,可以看到最终输出的是err4,第一个失败的返回值
const p13 = Promise.myAll([p1, p4, p5]).then(console.log).catch(console.log) // err4

// 4. 传入空数组
const p14 = Promise.myAll([]).then(console.log).catch(console.log) // []