我们在之前的一篇文章中 面试官问:Promise.all 使用、原理实现及错误处理 已经介绍过,当我们使用 Promise.all() 执行过个 promise 时,只要其中任何一个promise 失败都会执行 reject ,并且 reject 的是第一个抛出的错误信息,只有所有的 promise 都 resolve 时才会调用 .then 中的成功回调
- const p1 = Promise.resolve(1)
- const p2 = Promise.resolve(2)
- const p3 = new Promise((resolve, reject) => {
- setTimeout(reject, 1000, 'three');
- });
- Promise.all([p1, p2, p3])
- .then(values => {
- console.log('resolve: ', values)
- }).catch(err => {
- console.log('reject: ', err)
- })
- // reject: three
注意:其中任意一个 promise 被 reject ,Promise.all 就会立即被 reject ,数组中其它未执行完的 promise 依然是在执行的, Promise.all 没有采取任何措施来取消它们的执行
但大多数场景中,我们期望传入的这组 promise 无论执行失败或成功,都能获取每个 promise 的执行结果,为此,ES2020 引入了 Promise.allSettled()
Promise.allSettled()
Promise.allSettled() 可以获取数组中每个 promise 的结果,无论成功或失败
- const p1 = Promise.resolve(1)
- const p2 = Promise.resolve(2)
- const p3 = new Promise((resolve, reject) => {
- setTimeout(reject, 1000, 'three');
- });
- Promise.allSettled([p1, p2, p3])
- .then(values => {
- console.log(values)
- })
- /*
- [
- {status: "fulfilled", value: 1},
- {status: "fulfilled", value: 2},
- {status: "rejected", reason: "three"}
- ]
- */
当浏览器不支持 Promise.allSettled ,可以如此 polyfill:
- if (!Promise.allSettled) {
- const rejectHandler = reason => ({status: "rejected", reason})
- const resolveHandler = value => ({status: "fulfilled", value})
- Promise.allSettled = promises =>
- Promise.all(
- promises.map((promise) =>
- Promise.resolve(promise)
- .then(resolveHandler, rejectHandler)
- )
- // 每个 promise 需要用 Promise.resolve 包裹下
- // 以防传递非 promise
- );
- }
- // 使用
- const p1 = Promise.resolve(1)
- const p2 = Promise.resolve(2)
- const p3 = new Promise((resolve, reject) => {
- setTimeout(reject, 1000, 'three');
- })
- const promises = [p1, p2, p3]
- Promise.allSettled(promises).then(console.log)