# ❓ 介绍下 Promise.all 使用、原理实现及错误处理
# 使用介绍
Promise.all()
方法用于讲多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3])
# 原理实现
上面代码中,Promise.all()
方法接受一个数组作为参数,p1
、p2
、p3
都是 Promise 实例,如果不是,就会先调用下面讲到的 Promise.resolve
方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()
方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
p
的状态由 p1
、p2
、p3
决定,分成两种情况。
只有
p1
、p2
、p3
的状态都变成fulfilled
,p
的状态才会变成fulfilled
,此时p1
、p2
、p3
的返回值组成一个数组,传递给p
的回调函数。只要
p1
、p2
、p3
之中有一个被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
}
)
}
})
}
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: 报错了]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
上面代码中,p1
会 resolved
,p2
首先会 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: 报错了
2
3
4
5
6
7
8
9
10
11
12