Reputation: 121
So I was following along an MDN article on promises and was wondering how to modify the following code to be able to work for any number of files (not just 3).
function fetchAndDecode(url) {
return fetch(url).then(response => {
if(!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
} else {
if(response.headers.get("content-type") === "image/jpeg") {
return response.blob();
} else if(response.headers.get("content-type") === "text/plain") {
return response.text();
}
}
})
.catch(e => {
console.log(`There has been a problem with your fetch operation for resource "${url}": ` + e.message);
})
.finally(() => {
console.log(`fetch attempt for "${url}" finished.`);
})
}
let coffee = fetchAndDecode('coffee.jpg');
let tea = fetchAndDecode('tea.jpg');
let description = fetchAndDecode('description.txt');
Promise.all([coffee, tea, description]).then(values => {
console.log(values);
// Store each value returned from the promises in separate variables; create object URLs from the blobs
let objectURL1 = URL.createObjectURL(values[0]);
let objectURL2 = URL.createObjectURL(values[1]);
let descText = values[2];
// Display the images in <img> elements
let image1 = document.createElement('img');
let image2 = document.createElement('img');
image1.src = objectURL1;
image2.src = objectURL2;
document.body.appendChild(image1);
document.body.appendChild(image2);
// Display the text in a paragraph
let para = document.createElement('p');
para.textContent = descText;
document.body.appendChild(para);
});
MDN specifically notes that "If you were improving this code, you might want to loop through a list of items to display, fetching and decoding each one, and then loop through the results inside Promise.all(), running a different function to display each one depending on what the type of code was. This would make it work for any number of items, not just three." I'm not sure how to do this though, and would appreciate help. Thanks.
Upvotes: 0
Views: 828
Reputation: 349964
The second part of the code could be generalised as follows:
let urls = ['coffee.jpg', 'tea.jpg', 'description.txt'];
Promise.all(urls.map(fetchAndDecode)).then(values => {
let elem;
for (let value of values) {
if (value instanceof Blob) {
elem = document.createElement('img');
elem.src = URL.createObjectURL(value);
} else if (typeof value === "string") {
elem = document.createElement('p');
elem.textContent = value;
} else {
console.log("unexpected value type");
continue;
}
document.body.appendChild(elem);
}
});
Upvotes: 2
Reputation: 934
const resources = ['coffee.jpg', 'tea.jpg', 'description'];
const resourceRequests = resources.map(fetchAndDecode);
Promise.all(resourceRequests.then(values => {
...
Is one way to implement the suggestion. This approach allows for easier modification of the list of resources, but doesn't really change any of the Promise code.
The .map
code above is equivalent to (resource => fetchAndDecode(resource)) since fetchAndDecode
takes only the first argument that .map
would pass to it.
Upvotes: 0