Promise中这四个API原来这么简单!

502次阅读  |  发布于9月以前

一、前言

不管你是否还学的动,JS语言依然在以自己的节奏飞快的进化。Promise中的any()、race()、all()方法都是比较常见的;转眼间,Promise 的工具包里又多了一个方法Promise.allSettled 供你选择,它看起来像是对 Promise.all 的一种补充,缓解了使用 Promise.all 碰到reject 的痛点问题。

下面我们先来分别看下这四个方法及其区别:

二、Promise.any

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

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

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)
})

五、Promise.allSettled

从 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.any vs Promise.all

七、Promise.any vs Promise.race

八、Promise.all vs Promise.allSettled

一句话概括两者的最大不同:Promise.allSettled 永远不会被 reject

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8