0%

Promise常用方法使用(all,race,allsettled,any)

当我们在工作中需要批量处理异步操作时常会用到Promise的一些方法,那么这些方法都有怎样的特点和区别呢?接下来我们逐个的来分析下:

Promise.all()

我们先来看下MDN中的定义:

Promise.all() 静态方法接受一个 Promise 可迭代对象作为输入,并返回一个 Promise。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。

上述文档总结如下:

  • Promise.all()参数为包含多个Promise实例的数组
  • 当所有实例都执行成功时,返回他们所有的成功值
  • 如果有任何一个出现错误,则变为rejected状态并返回第一个错误的原因

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const delay = (time, flag, data) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(flag) {
resolve(data)
}else{
reject(`Error ${data}`)
}
}, time)
})
}

const p1 = delay(1000, true, 1)
const p2 = delay(2000, true, 2)
const p3 = delay(3000, true, 3)

Promise.all([p2, p3, p1]).then(res => {
console.log(res) // [2, 3, 1]
}).catch(e => console.log(e))

上面例子为所有promise实例全部成功的例子,因为返回结果为[2, 3, 1],由此我们也可以看到返回结果的顺序和参数传递的顺序是一致的。接下来我们看一个不成功的例子:

1
2
3
4
5
6
7
const p1 = delay(1000, true, 1)
const p2 = delay(2000, false, 2)
const p3 = delay(3000, true, 3)

Promise.all([p2, p3, p1]).then(res => {
console.log(res)
}).catch(e => console.log(e)) // Error 2

上述例子中p2状态为拒绝,所以Promise.all()最终状态也为Rejected并将p2的错误返回。

细心的你一定看出了问题,p1的成功结果去哪了?没错,Promise.all()方法在遇到错误的时候不会返回已经处在fulfilled状态的实例的数据,针对这个问题,我们来看一下Promise.allsettled()方法。

Promise.allSettled()

Promise.allSettled() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个单独的 Promise。当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组。

简单来说,Promise.allSettled方法不管参数中的promise对象成功与否,他都会等待所有promise状态的确认并且返回一个包含结果的对象数组。

接下来我们还是看刚才的例子:

1
2
3
4
5
6
7
const p1 = delay(1000, true, 1)
const p2 = delay(2000, true, 2)
const p3 = delay(3000, true, 3)

Promise.allSettled([p2, p3, p1]).then(res => {
console.log(res)
}).catch(e => console.log(e))

返回的res内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[
{
"status": "fulfilled",
"value": 2
},
{
"status": "fulfilled",
"value": 3
},
{
"status": "fulfilled",
"value": 1
}
]

再来看看错误状态的情况:

1
2
3
const p1 = delay(1000, true, 1)
const p2 = delay(2000, false, 2)
const p3 = delay(3000, false, 3)

返回信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[
{
"status": "rejected",
"reason": "Error 2"
},
{
"status": "rejected",
"reason": "Error 3"
},
{
"status": "fulfilled",
"value": 1
}
]

至此,我们看到一旦所指定的 promises 集合中每一个 promise 已经完成,无论是成功的达成或被拒绝,未成功的 Promise将被异步完成。那时,所返回的 promise 的处理器将传入一个数组作为输入,该数组包含原始 promises 集中每个 promise 的结果。

对于每个结果对象,都有一个 status 字符串。如果它的值为 fulfilled,则结果对象上存在一个 value 。如果值为 rejected,则存在一个 reason 。value(或 reason )反映了每个 promise 成功(或拒绝)的值。

Promise.race()

Promise.race() 静态方法接受一个 promise 可迭代对象作为输入,并返回一个 Promise。这个返回的 promise 会随着第一个 promise 的敲定而敲定。

race的中文含义为”赛跑“,所以这个方法就很好理解了,拿上面的例子来说,3个promise实例谁先完成(不论成功还是失败)都将会以此作为race方法的结果而被确定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const p1 = delay(1000, true, 1)
const p2 = delay(2000, true, 2)
const p3 = delay(3000, true, 3)

Promise.race([p2, p3, p1]).then(res => {
console.log(res) // 1
}).catch(e => console.log(e))

const p1 = delay(1000, false, 1)
const p2 = delay(2000, true, 2)
const p3 = delay(3000, true, 3)

Promise.race([p2, p3, p1]).then(res => {
console.log(res)
}).catch(e => console.log(e)) // Error 1

就这个例子来说,Promise.race()方法的结果成功与否完全取决于p1,因为它总会第一个完成(或失败)。

Promise.any()

Promise.any() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个 Promise。当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝。

Promise.any()主要是针对只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。

他还有一个特点就是:

Promise.any()不会因为某个 Promise 变成rejected状态而结束,必须等到所有参数 Promise 变成rejected状态才会结束。

看下例子:

1
2
3
4
5
6
7
const p1 = delay(1000, false, 1)
const p2 = delay(2000, false, 2)
const p3 = delay(3000, true, 3)

Promise.any([p2, p3, p1]).then(res => {
console.log(res) // 3
}).catch(e => console.log(e))

上述例子中,只有p3是成功状态,因此包装实例的状态就是p3的状态,这里res输出3。

1
2
3
4
5
6
7
const p1 = delay(1000, false, 1)
const p2 = delay(2000, false, 2)
const p3 = delay(3000, false, 3)

Promise.any([p2, p3, p1]).then(res => {
console.log(res)
}).catch(e => console.log(e)) // AggregateError: All promises were rejected

如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promiseAggregateError 类型的实例,它是 Error 的一个子类,用于把单一的错误集合在一起。

总结

作用:

  • Promise.all() 全成功我成功 失败一个我失败
  • Promise.race() 谁第一个改变状态就是谁的,无论成功或失败
  • Promise.allSettled() 管你成功或失败,全部都得运行完
  • Promise.any() 一个成功我成功,全部失败我失败

状态成功时返回值:

  • Promise.all() 返回状态成功时的数组
  • Promise.race() 第一个成功的
  • Promise.allSettled() 无所谓成功或失败,返回值都是一个包含状态对象的数组
  • Promise.any() 返回第一个成功的

状态失败时返回值:

  • Promise.all() 第一个失败的
  • Promise.race() 第一个失败的
  • Promise.allSettled() 无所谓成功或失败,返回值都是一个包含状态对象的数组
  • Promise.any() AggregateError: All promises were rejected

是否将参数数组内部的Promise实例全部执行完,才调用

  • Promise.all() 成功是是,失败是否
  • Promise.race() 不是
  • Promise.allSettled() 是
  • Promise.any() 成功是否,失败是是