Promise.all API 的出错处理

148 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,点击查看活动详情

如果任何一个 Promise 被 reject,Promise.all 返回的 Promise 会立即拒绝该错误。

以下是一个例子:

Promise.all([
  new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
  new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000)),
  new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
]).catch(alert); // Error: Whoops!

会打印:Error: Whoops!

这里第二个 Promise 在两秒钟内被拒绝。 这导致立即拒绝 Promise.all,因此 .catch 执行:拒绝错误成为整个 Promise.all 的结果。

如果一个 Promise 被 reject,Promise.all 会立即被 reject ,此时完全忽略列表中的其他 Promise——其结果被忽略了。

例如,如果有多个 fetch 调用,就像上面的例子一样,一个失败了,其他的 fetch 仍然会继续执行,但是 Promise.all 不会再监视它们了。 他们的结果将被忽略。

Promise.all 不会 cancel 这些 Promise 对象,因为 Promise 中没有 cancel 的概念。

技术上说,存在可以帮助解决此问题的 AbortController,但它不是 Promise API 的一部分。

通常, Promise.all(...) 接受一个可迭代的(在大多数情况下是一个数组)的 Promise. 但是,如果这些对象中的任何一个不是 Promise,它就会 按原样 传递给结果数组。

例如,这里的结果是 [1, 2, 3]:

下面是一个例子:

Promise.all([
  new Promise((resolve, reject) => {
    setTimeout(() => resolve(1), 1000)
  }),
  2,
  3
]).then(alert); // 1, 2, 3

如果任何一个 Promise 被拒绝,Promise.all 将作为一个整体被 reject.

当我们需要所有结果成功才能继续时,这对于“全有或全无”的情况很有用:

Promise.all([
  fetch('/template.html'),
  fetch('/style.css'),
  fetch('/data.json')
]).then(render); // render method needs results of all fetches

这从原理上说,有点像数据库操作中的原子操作 概念。

Promise.allSettled 只是等待所有的 Promise 完成,不管结果如何。 结果数组有下列两种情况:

  • {status:"fulfilled", value:result} 成功响应
  • {status:"rejected", reason:error} 表示错误。

例如,我们想获取有关多个 github 用户的信息。 即使一个请求失败,我们仍然对其他请求感兴趣。

这种场景适合使用 Promise.allSettled

let urls = [
  'https://api.github.com/users/iliakan',
  'https://api.github.com/users/remy',
  'https://no-such-url'
];

Promise.allSettled(urls.map(url => fetch(url)))
  .then(results => { // (*)
    results.forEach((result, num) => {
      if (result.status == "fulfilled") {
        alert(`${urls[num]}: ${result.value.status}`);
      }
      if (result.status == "rejected") {
        alert(`${urls[num]}: ${result.reason}`);
      }
    });
  });

传递到 then 回调函数里的输入参数,results 数组为:

[
  {status: 'fulfilled', value: ...response...},
  {status: 'fulfilled', value: ...response...},
  {status: 'rejected', reason: ...error object...}
]

对于每个 Promise 对象,我们要么得到 value 值,要么得到引起错误的 reason 值。