I am updating my javascript skills with Promises, already have in place a library with XHR and callbacks to load and inject multiple files at once and only proceed if ALL of them succeeded.
I am trying to use Promise.all() and Fetch API to get a similar functionality but can't make it work: console.log('All the promises are resolved', values); always triggers no matter if some of the fetch promises failed.
I want to be able to execute the code below, and only proceed with nowInitialize function if all the files were able to be fetched, or throw error using catch() with the reason of the first file that failed
xRequire(['index.html', 'style.cds'])
.then(nowInitialize)
.catch(reason => 'One or more files failed to load' + reason)
style.cds will obviously fail
//TODO Handle file types appropriately
//TODO: Inject css, javascript files
function xRequire(files) {
let urls = [];
let promisesList = [];
let handleAllPromises;
//Populates urls with each file required
for(let i=0; i < files.length ; i++) {
urls.push(files[i]);
}
//Fetch each file in urls
urls.forEach( (url, i) => { // (1)
promisesList.push(
fetch(url)
.then(handleResponse)
.then(data => console.log(data))
.catch(error => console.log(error))
);
});
handleAllPromises = Promise.all(promisesList);
handleAllPromises.then(function(values) {
console.log('All the promises are resolved', values);
});
handleAllPromises.catch(function(reason) {
console.log('One of the promises failed with the following reason', reason);
});
}
function handleResponse(response) {
let contentType = response.headers.get('content-type');
console.log('Requested Info: ' + contentType);
if (contentType.includes('application/json')) {
return handleJSONResponse(response);
} else if (contentType.includes('text/html')) {
return handleTextResponse(response);
} else if (contentType.includes('text/css')) {
return handleTextResponse(response);
} else if (contentType.includes('application/javascript')) {
return handleTextResponse(response);
} else {
throw new Error(`Sorry, content-type ${contentType} not supported`);
}
}
function handleJSONResponse(response) {
return response.json()
.then(json => {
if (response.ok) {
return json;
} else {
return Promise.reject(Object.assign({}, json, {
status: response.status,
statusText: response.statusText
}));
}
});
}
function handleTextResponse(response) {
return response.text()
.then(text => {
if (response.ok) {
return text;
} else {
return Promise.reject({
status: response.status,
statusText: response.statusText,
err: text
});
}
});
}
Can you just rewrite it as async-await code? Here is a rough idea of the typical flow:
const [data1, data2, data3] = await Promise.all([
fetch(url1),
fetch(url2),
fetch(url3),
]);
In other words, Promise.all() returns the promise to all the data that is returned from your multiple fetch() functions.
Then, if you put this into a try-catch, you can handle the rejection as well:
try {
const [data1, data2, data3] = await Promise.all([
fetch(url1),
fetch(url2),
fetch(url3),
]);
// Now you can process the data:
[data1, data2, data3].map(handleResponse);
} catch (error) {
console.log('Error downloading one or more files:', error);
}
If you want to loop with async-await, you can do that:
const promises = [];
for (const url of [url1, url2, url3, url4]) {
promises.push(fetch(url));
}
const [data1, data2, data3, data4] = await Promise.all(promises);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With