谨慎使用Promise.all

有一天, QA跟我抱怨,用户信息页面挂掉了, 整个页面的是空白的(无数据)。
打开浏览器调试了一下,发现只是一个获取用户爱好的接口挂掉了。那么一个接口挂掉了为什么会导致整个页面无数据呢?

先定位一下出问题的代码:

Promise.all([occupations(), hobbies(), vehicles(), user()])
  .then(res => {
    this.occupationItems = res[0]
    this.hobbiesItems = res[1] // 这个数据拿不到
    this.vehiclesItems = res[2]
    this.user = res[3]
  })
  .catch(console.error)

这是用户信息页面的代码,用途是请求用户职业,喜好,名下车辆,用户详情等信息。请求回来之后,统一在then里面进行处理。
回忆一下promise.all的用法: 传递一个promise的数组,当所有的promise都完成(resolved),回调所有成功的结果, 或者有一个失败, 回调第一个失败的结果
在当前状况下, hobbies接口返回500promise变成rejected状态,然后就不会执行then回调了。

为什么要用Promise.all呢?
promise.all将多个promise放在一起处理,能简化回调的处理,一个then回调拿到所有数据进行处理,也能一个catch回调捕获所有的异常。不然我们的代码得变成这样:

hobbies()
  .then(hobbiesItems => { this.hobbiesItems = hobbiesItems })
  .catch(console.error)

occupations()
  .then(occupationItems => { this.occupationItems = occupationItems })
  .catch(console.error)

vehicles()
  .then(vehicleItems => { this.vehiclesItems = vehicleItems })
  .catch(console.error)

user()
  .then(currentUser => { this.user = currentUser })
  .catch(console.error)

但是!!!

那么就意味着以下两点:

  1. 如果有一个回调执行失败,then是不会执行的,或者说,所有的promise也都失败了
  2. 即使有几个promise已经进入resolved状态,也会阻塞在那里直到所有的promise完成

第一点会使得项目的容错大大降低,也许可能只是一个不关键的数据加载失败,其他所有的数据也不会显示。
第二点有违JavaScript非阻塞的理念,如果一个回调迟迟不能拿到结果,大家就都干等着了。。

随手搜索了一下项目中的Promise.all,心情复杂。。。

随处可见的的Promise.all

什么时候可以使用Promise.all

出于一个Promise失败会影响所有Promise回调执行以及promise.all会有一些阻塞的情况,我们应该谨慎使用。 那么我们什么情况可以使用Promise.all呢?我个人认为只有以下情况:
几个异步操作是强相关的,后续步骤必须依赖这几个步骤全部成功才能进行。
比如假设一个支付操作需要用户账户有余额,并且商品有库存,才能进行下一步操作,那么我们也许需要Promise.all来处理。

Promise.all([getUserBalance(), getInventory()])
.then(() => {
  // 做一些下单和支付的操作
})
.catch(error => alert(`can't pay: ${error.message}`))

所以, 你的项目中有滥用Promise.all的情况吗?

你可能感兴趣的:(谨慎使用Promise.all)