回到课程
本资料仅提供以下语言版本:English, Русский。请 帮助我们 将其翻译为 简体中文 版本。

容错机制 Promise.all

我们想要并行获取多个 URL。

执行此操作代码如下:

let urls = [
  'https://api.github.com/users/iliakan',
  'https://api.github.com/users/remy',
  'https://api.github.com/users/jeresig'
];

Promise.all(urls.map(url => fetch(url)))
  // for each response show its status
  .then(responses => { // (*)
    for(let response of responses) {
      alert(`${response.url}: ${response.status}`);
    }
  ));

问题是如果任何请求都失败了,那么 Promise.all 就会 reject error,而且所有的其他请求结果都会丢失。

这并不好。

修改代码会导致 (*) 行的 responses 数组包含成功响应的对象和失败时获取的 error 对象。

例如,如果其中一个 URL 失效,那么就会变成这样:

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

Promise.all(...) // your code to fetch URLs...
  // ...and pass fetch errors as members of the resulting array...
  .then(responses => {
    // 3 urls => 3 array members
    alert(responses[0].status); // 200
    alert(responses[1].status); // 200
    alert(responses[2]); // TypeError: failed to fetch (text may vary)
  });

P.S. 在这个任务中,你无需使用 response.text()response.json() 来加载完整的请求。只要正确处理 fetch 的 error 即可。

打开一个任务沙箱。

实际上解决方案非常简单。

就像这样:

Promise.all(
  fetch('https://api.github.com/users/iliakan'),
  fetch('https://api.github.com/users/remy'),
  fetch('http://no-such-url')
)

这里我们有一个指向 Promise.allfetch(...) promise 数组。

我们不能改变 Promise.all 的工作方式:如果它检测到 error,就会 reject 它。因此我们需要避免任何 error 发生。相反,如果 fetch 发生 error,我们需要将其视为“正常”结果。

就像这样:

Promise.all(
  fetch('https://api.github.com/users/iliakan').catch(err => err),
  fetch('https://api.github.com/users/remy').catch(err => err),
  fetch('http://no-such-url').catch(err => err)
)

换句话说,.catch 会对所有的 promise 产生 error,然后正常返回。根据 promise 的工作原理,只要 .then/catch 处理器返回值(无论是 error 对象或其他内容),执行流程就会“正常”进行。

因此 .catch 会将 error 作为“正常”结果返回给外部的 Promise.all

代码如下:

Promise.all(
  urls.map(url => fetch(url))
)

可重写为:

Promise.all(
  urls.map(url => fetch(url).catch(err => err))
)

使用沙箱打开解决方案。