Reputation: 2635
my aim is to fetch data from two URLs and perform an action only when both have come back successfully. On the other hand i want to return an error if either of them fail. I have played around with my code and managed to get the desired effect.
My question is, is there a more efficient, succinct way of achieving the same functionality?
Helper functions
let status = (r) => {
if (r.ok) {
return Promise.resolve(r)
} else {
return Promise.reject(new Error(r.statusText))
}
}
let json = (r) => r.json();
Requests
let urls = [
'http://localhost:3000/incomplete',
'http://localhost:3000/complete'
]
let promises = urls.map(url => {
return fetch(url)
.then(status)
.then(json)
.then(d => Promise.resolve(d))
.catch(e => Promise.reject(new Error(e)));
});
Promise.all(promises).then(d => {
// do stuff with d
}).catch(e => {
console.log('Whoops something went wrong!', e);
});
Upvotes: 3
Views: 21776
Reputation: 22692
// https://jsonplaceholder.typicode.com - Provides test JSON data
var urls = [
'https://jsonplaceholder.typicode.com/todos/1',
'https://jsonplaceholder.typicode.com/todos/2',
'https://jsonplaceholder.typicode.com/posts/1',
'https://jsonplaceholder.typicode.com/posts/2'
];
// Maps each URL into a fetch() Promise
var requests = urls.map(function(url){
return fetch(url)
.then(function(response) {
// throw "uh oh!"; - test a failure
return response.json();
})
});
// Resolve all the promises
Promise.all(requests)
.then((results) => {
console.log(JSON.stringify(results, null, 2));
}).catch(function(err) {
console.log("returns just the 1st failure ...");
console.log(err);
})
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
Upvotes: 5
Reputation: 1756
const urls = [
'http://localhost:3000/incomplete',
'http://localhost:3000/complete'
]
const json = (r) => r.json()
const status = (r) => r.ok ? Promise.resolve(r) : Promise.reject(new Error(r.statusText))
const toRequest = url => fetch(url).then(status).then(json)
const onError = e => { console.log('Whoops something went wrong!', e) }
const consumeData = data => { console.log('data: ', data) }
Promise.all(urls.map(toRequest))
.then(consumeData)
.catch(onError)
Upvotes: 4
Reputation: 42450
Use fetchOk for nicer error messages, and destructuring to access the results:
let fetchOk = (...args) => fetch(...args)
.then(res => res.ok ? res : res.json().then(data => {
throw Object.assign(new Error(data.error_message), {name: res.statusText});
}));
Promise.all([
'http://localhost:3000/incomplete',
'http://localhost:3000/complete'
].map(url => fetchOk(url).then(r => r.json()))).then(([d1, d2]) => {
// do stuff with d1 and d2
}).catch(e => console.error(e));
// Work around stackoverflow's broken error logger.
var console = { error: msg => div.innerHTML += msg + "<br>" };
<div id="div" style="white-space: pre;"></div>
Upvotes: 2