# ❓ 介绍下 Promise.all 使用、原理实现及错误处理

# 使用介绍

Promise.all()方法用于讲多个 Promise 实例,包装成一个新的 Promise 实例。

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

# 原理实现

上面代码中,Promise.all()方法接受一个数组作为参数,p1p2p3 都是 Promise 实例,如果不是,就会先调用下面讲到的 Promise.resolve 方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。

p 的状态由 p1p2p3 决定,分成两种情况。

  1. 只有p1p2p3的状态都变成fulfilledp的状态才会变成fulfilled,此时p1p2p3的返回值组成一个数组,传递给p的回调函数。

  2. 只要p1p2p3之中有一个被rejected,p 的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

不完全实现

Promise.all = function (promises) {
  // 只考虑传入的 promises 为数组的情况
  return new Promise((resolve, reject) => {
    const length = promises.length
    let result = []
    if (!length) return resolve(result)
    for (let index = 0; index < length; index++) {
      const item = promises[index]
      // 这里考虑 item 不是 Promise 对象
      Promise.resolve(item).then(
        (res) => {
          result[index] = res
          // 所有的 promises 状态都是 fulfilled,promise.all返回的实例才变成 fulfilled 状态
          if (result.length === length) resolve(result)
        },
        (err) => {
          reject(err)
          return
        }
      )
    }
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 错误处理

注意,如果作为参数的 Promise 实例,自己定义了 catch 方法,那么它一旦被 rejected,并不会触发 Promise.all()catch 方法。

const p1 = new Promise((resolve, reject) => {
  resolve('hello')
})
  .then((result) => result)
  .catch((e) => e)

const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了')
})
  .then((result) => result)
  .catch((e) => e)

Promise.all([p1, p2])
  .then((result) => console.log(result))
  .catch((e) => console.log(e))
// ["hello", Error: 报错了]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

上面代码中,p1resolvedp2 首先会 rejected,但是 p2 有自己的 catch 方法,该方法返回的是一个新的 Promise 实例,p2 指向的实际上是这个实例。该实例执行完 catch 方法后,也会变成 resolved,导致 Promise.all()方法参数里面的两个实例都会 resolved,因此会调用 then 方法指定的回调函数,而不会调用 catch 方法指定的回调函数。

如果 p2 没有自己的 catch 方法,就会调用 Promise.all()catch 方法。

const p1 = new Promise((resolve, reject) => {
  resolve('hello')
}).then((result) => result)

const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了')
}).then((result) => result)

Promise.all([p1, p2])
  .then((result) => console.log(result))
  .catch((e) => console.log(e))
// Error: 报错了
1
2
3
4
5
6
7
8
9
10
11
12

Promise.resolve()