This commit is contained in:
Ilya Kantor 2019-03-13 23:08:35 +03:00
parent e60bb12707
commit 5ca83ba7ba
24 changed files with 144 additions and 137 deletions

View file

@ -0,0 +1,44 @@
The solution is actually pretty simple.
Take a look at this:
```js
Promise.all(
fetch('https://api.github.com/users/iliakan'),
fetch('https://api.github.com/users/remy'),
fetch('http://no-such-url')
)
```
Here we have an array of `fetch(...)` promises that goes to `Promise.all`.
We can't change the way `Promise.all` works: if it detects an error, then it rejects with it. So we need to prevent any error from occurring. Instead, if a `fetch` error happens, we need to treat it as a "normal" result.
Here's how:
```js
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)
)
```
In other words, the `.catch` takes an error for all of the promises and returns it normally. By the rules of how promises work, if a `.then/catch` handler returns a value (doesn't matter if it's an error object or something else), then the execution continues the "normal" flow.
So the `.catch` returns the error as a "normal" result into the outer `Promise.all`.
This code:
```js
Promise.all(
urls.map(url => fetch(url))
)
```
Can be rewritten as:
```js
Promise.all(
urls.map(url => fetch(url).catch(err => err))
)
```

View file

@ -0,0 +1,24 @@
<!DOCTYPE HTML>
<html>
<body>
<script>
let urls = [
'https://api.github.com/users/iliakan',
'https://api.github.com/users/remy',
'http://no-such-url'
];
Promise.all(
urls.map(url => fetch(url).catch(err => err))
)
.then(responses => {
alert(responses[0].status); // 200
alert(responses[1].status); // 200
alert(responses[2]); // TypeError: failed to fetch (text may vary)
});
</script>
</body>
</html>

View file

@ -0,0 +1,28 @@
<!DOCTYPE HTML>
<html>
<body>
<script>
// if any of URLs fails, other results are ignored
// change that:
// make errors appear as members of the responses array, together with normal results
let urls = [
'https://api.github.com/users/iliakan',
'https://api.github.com/users/remy',
'http://no-such-url'
];
// Fix me:
Promise.all(urls.map(url => fetch(url)))
// Demo output (no need to change):
.then(responses => {
alert(responses[0].status); // 200
alert(responses[1].status); // 200
alert(responses[2]); // TypeError: failed to fetch (text may vary)
});
</script>
</body>
</html>

View file

@ -0,0 +1,48 @@
# Fault-tolerant Promise.all
We'd like to fetch multiple URLs in parallel.
Here's the code to do that:
```js run
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}`);
}
});
```
The problem is that if any of requests fails, then `Promise.all` rejects with the error, and we lose results of all the other requests.
That's not good.
Modify the code so that the array `responses` in the line `(*)` would include the response objects for successful fetches and error objects for failed ones.
For instance, if one of URLs is bad, then it should be like:
```js
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. In this task you don't have to load the full response using `response.text()` or `response.json()`. Just handle fetch errors the right way.