不管你是否还学的动,JS语言依然在以自己的节奏飞快的进化。Promise中的any()、race()、all()方法都是比较常见的;转眼间,Promise 的工具包里又多了一个方法Promise.allSettled 供你选择,它看起来像是对 Promise.all 的一种补充,缓解了使用 Promise.all 碰到reject 的痛点问题。
下面我们先来分别看下这四个方法及其区别:
Promise.any()
方法将一组可迭代的 Promises 作为输入,并返回一个 Promise,只要参数实例有一个变成 fulfilled 状态,包装实例就会变成 fulfilled 状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
const promises = [
Promise.reject('ERROR A'),
Promise.reject('ERROR B'),
Promise.resolve('result'),
]
Promise.any(promises).then((value) => {
console.log('value: ', value) // value: result
}).catch((err) => {
console.log('err: ', err)
})
如果所有传入的 promises
都失败:
const promises2 = [
Promise.reject('ERROR A'),
Promise.reject('ERROR B'),
Promise.reject('ERROR C'),
]
Promise.any(promises2).then((value) => {
console.log('value:', value)
}).catch((err) => {
console.log('err:', err)
console.log(err.errors)
})
Promise.race()
方法将一组可迭代的 Promises 作为输入,并返回一个 Promise ,顾名思义,race 就是赛跑的意思,Promise.race([p1, p2, p3]) 里面哪个结果获得的快,就返回那个结果。
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one')
})
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two')
})
Promise.race([promise1, promise2]).then((value) => {
console.log(value) // 'two'
})
Promise.all()
方法将一组可迭代的 Promises 作为输入,并返回一个 Promise ,该 Promise resolve 的结果为刚才那组输入 promises 的返回结果。
const promise1 = Promise.resolve(3)
const promise2 = 42
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo')
})
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values) // [3, 42, "foo"]
})
当三个 promise 都完成时,Promise.all
就完成了,并且输出被打印了。如果其中一个 promise 失败了,则 Promise.all 整体将会失败。
const promise1 = Promise.resolve(3)
const promise2 = Promise.reject('error')
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo')
})
Promise.all([promise1, promise2, promise3])
.then(values => ...)
.catch(err => console.log(err)) // 'error'
当需要处理多个 Promise 并行时,大多数情况下 Promise.all 用起来是非常顺手的,但是一旦有一个promise 出现了异常(reject),情况就会变的麻烦。尽管能用 catch 捕获其中的异常,但你会发现其他执行成功的 Promise 的消息都丢失了,仿佛石沉大海一般。
要么全部成功,要么全部重来,这是 Promise.all 本身的强硬逻辑,也是痛点的来源,这给 Promise.allSettled 留下了立足的空间。
问题:Promise.all 如果有报错,是在 then 还是 catch 接收数据?
let p1 = Promise.resolve(1)
let p2 = Promise.resolve(2)
let p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, "3")
});
let p4 = Promise.reject(4)
let p5 = Promise.reject(5).catch((e) => e)
// 情况1:promise全部resolve
Promise.all([p1, p2, p3]).then(values => {
console.log(values) // 其中p1、p2、p3都成功,所以进入then()
}).catch(function(err) {
console.log(err) // 永远走不到这里
});
// 情况2:promise有一个reject,且reject没有主动捕获异常
Promise.all([p1, p2, p4]).then(values => {
console.log(values) // 其中p4失败,且没有主动捕获异常,永远走不到这里
}).catch(function(err) {
console.log(err) // 此时走到catch 4
});
// 情况3:promise有一个reject,且reject主动捕获异常
Promise.all([p1, p2, p5]).then(values => {
console.log(values) // 其中p5失败,但是主动捕获了p5的异常,所以进入then()
}).catch(function(err) {
console.log(err) // 永远走不到这里
});
// 情况4:使用Promise.allSettled
Promise.allSettled([p1, p2, p4]).then(values => {
console.log(values) // 其中p4失败,但是使用Promise.allSettled,所以进入then()
}).catch(function(err) {
console.log(err)
})
从 ES2020 开始,你可以使用 Promise.allSettled
。当所有的 promises 都已经结束无论是完成状态或者是失败状态,它都会返回一个 promise,这个 promise 将会包含一个关于描述每个 promise 状态结果的对象数组。
const promise1 = Promise.resolve(3)
const promise2 = Promise.reject(new Error('An error'))
const promise3 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'))
const promises = [promise1, promise2, promise3]
Promise.allSettled(promises).then((res) => console.log(res))
Promise.all()
:任意一个 promise 被 reject ,就会立即被 reject ,并且 reject 的是第一个抛出的错误信息;只有所有的 promise 都 resolve 时整体才会 resolve。Promise.any()
:任意一个 promise 被 resolve ,就会立即被 resolve ,并且 resolve 的是第一个正确结果;只有所有的 promise 都 reject 时整体才会 reject。Promise.race()
:返回最先完成的 promise 的结果,无论成功还是失败;假如第一个 promise 失败了,那么就会结束。Promise.any()
:不会因为某个 Promise 变成 rejected 而结束,哪怕首个 promise 是 rejected,可能还会有另一个 promise 成功。一句话概括两者的最大不同:Promise.allSettled 永远不会被 reject
Promise.all
将在 Promises 数组中的其中一个 Promises 失败后立即失败。Promise.allSettled
将永远不会失败,一旦数组中的所有 Promises 被完成或失败,它就会完成。Promise.allSettled
是对 Promise.all 的一种补充,解决了当多个 promise 并行时 reject 的出现会伴随着其他 promise 数据丢失的问题。Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8