I am currently learning async await fetch
and I've created the following example to help me learn.
The working example below:
- fetches three random json records from a Public API
- extracts the
url
from each returnjson
- creates three
img
elements - appends three
img
elements to the document body.
Notice that promise2
has an intentionally wrong path set to force a http status 404.
How do I handle this error if it was to happen to any of the three promises?
// the big promise.
async function getAsyncData() {
try {
// attempt to resolve 3 individual unrelated promises...
let promise1 = await fetch('.jpg&text=.jpg');
let promise2 = await fetch('.png&text=.png');
let promise3 = await fetch('.gif&text=.gif');
// we create an html img element and set its src attribute to the thumbnailUrl...
var img = document.createElement('img');
img.src = promise1.url;
// ...and add it to our html document body...
document.body.append(img);
// we create an html img element and set its src attribute to the thumbnailUrl...
var img = document.createElement('img');
img.src = promise2.url;
// ...and add it to our html document body...
document.body.append(img);
// we create an html img element and set its src attribute to the thumbnailUrl...
var img = document.createElement('img');
img.src = promise3.url;
// ...and add it to our html document body...
document.body.append(img);
} catch (error) {
console.log('Try/Catch block error:', error);
}
// return {
// }
}
getAsyncData();
I am currently learning async await fetch
and I've created the following example to help me learn.
The working example below:
- fetches three random json records from a Public API
- extracts the
url
from each returnjson
- creates three
img
elements - appends three
img
elements to the document body.
Notice that promise2
has an intentionally wrong path set to force a http status 404.
How do I handle this error if it was to happen to any of the three promises?
// the big promise.
async function getAsyncData() {
try {
// attempt to resolve 3 individual unrelated promises...
let promise1 = await fetch('https://dummyimage./48x48/4caf50/ffffff.jpg&text=.jpg');
let promise2 = await fetch('https://dummyimage./bad/url/here/48x48/e91e63/ffffff.png&text=.png');
let promise3 = await fetch('https://dummyimage./48x48/00bcd4/ffffff.gif&text=.gif');
// we create an html img element and set its src attribute to the thumbnailUrl...
var img = document.createElement('img');
img.src = promise1.url;
// ...and add it to our html document body...
document.body.append(img);
// we create an html img element and set its src attribute to the thumbnailUrl...
var img = document.createElement('img');
img.src = promise2.url;
// ...and add it to our html document body...
document.body.append(img);
// we create an html img element and set its src attribute to the thumbnailUrl...
var img = document.createElement('img');
img.src = promise3.url;
// ...and add it to our html document body...
document.body.append(img);
} catch (error) {
console.log('Try/Catch block error:', error);
}
// return {
// }
}
getAsyncData();
Share
Improve this question
edited May 29, 2020 at 6:40
suchislife
asked May 26, 2020 at 17:11
suchislifesuchislife
1
7
-
1
Try
Promise.allSettled
. It doesn't reject everything in the case where just one promise rejects (which is whatPromise.all
would do). Another note is that yourfetch
es can't be parallel if you useawait
the way you are in your example. – zero298 Commented May 26, 2020 at 17:22 -
I see. Ok. So as for
fetch
being unable to be parallel... Argh! Youtube examples... Are you proposing Iawait
thefetch
and thenawait
ajson
of thefetch
? – suchislife Commented May 26, 2020 at 17:24 - Updated code to reflect what I think you meant. – suchislife Commented May 26, 2020 at 17:30
- 1 @suchislife, build the Promises into an array, and use a for await of loop to iterate on the Promises. That way you get the best of both worlds (depending on what you are trying to do) – user120242 Commented May 26, 2020 at 17:31
-
1
I'm on FF 68 which doesn't support
allSettled
. I would put all thefetch
es into an array and use them there. It's OK to mix Promises and async/await. It's all about ease of use and trying to avoid callback hell. It lets us write synchronous looking code. – zero298 Commented May 26, 2020 at 17:47
2 Answers
Reset to default 5Using Promise.allSettled you can run all the fetch calls in parallel and wait for them all to plete.
const test = async() => {
const promise1 = await fetch('https://dummyimage./48x48/4caf50/ffffff.jpg&text=.jpg')
.then(r => r.url)
const promise2 = await fetch('https://dummyimage./bad/url/here/48x48/e91e63/ffffff.png&text=.png')
.then(r => r.url)
const promise3 = await fetch('https://dummyimage./48x48/00bcd4/ffffff.gif&text=.gif')
.then(r => r.url)
const results = await Promise.allSettled([promise1, promise2, promise3])
console.log(results);
}
test();
For older support you would need to use a promise that would catch any errors from the fetch.
function makeCall () {
return new Promise((resolve) => {
fetch('https://dummyimage./48x48/4caf50/ffffff.jpg&text=.jpg')
.then(r => console.log(r.url))
.catch(error => resolve({ error }))
})
}
const test = async() => {
const promise1 = makeCall()
const promise2 = makeCall()
const promise3 = makeCall()
const results = await Promise.all([promise1, promise2, promise3])
console.log(results)
}
test()
.error and try/catch is not what you are looking for:
fetch resolves even if 404?
You need to check the value of response.ok
. fetch only throws errors on network problems, not error responses.
// Background Colors
const bgHexColors = ['f44336', 'e91e63', '9c27b0', '673ab7', '3f51b5', '2196f3', '03a9f4', '00bcd4', '009688', '4caf50', '8bc34a', 'cddc39', 'ffeb3b', 'ffc107', 'ff9800', 'ff5722', '795548', '9e9e9e', '607d8b'];
// Foreground Colors
const fgHexColors = ['ffffff'];
// Image File Extensions
const imgExtensions = ['.png', '.gif', '.jpg'];
// First, we initialize an empty array for promises.
let myPromises = [];
// We then populate this array with 24 promises.
for(let i = 0; i < 24; i++){
let imgWidth = 48;
let imgHeight = 48;
let bgHexColor = bgHexColors[Math.floor(Math.random() * bgHexColors.length)];
let fgHexColor = fgHexColors[Math.floor(Math.random() * fgHexColors.length)];
let imgExtension = imgExtensions[Math.floor(Math.random() * imgExtensions.length)];
let imgText = imgExtension;
// We declare the promise to be added and...
let myPromise = getRandomImage(imgWidth, imgHeight, bgHexColor, fgHexColor, imgExtension, imgText);
// add each promise to the myPromises array.
myPromises.push(myPromise);
}
// We create an html span element and...
let span = document.createElement('span');
span.style.color = '#ffffff';
// We set the element's span text to Please wait...
span.innerText = 'Please wait...';
// We add the span element to the document body.
document.body.append(span);
// Promise.all requires an array.
Promise.all(myPromises).then((myResponses) => {
// debug
// console.log(myResponses);
// We create an html img element and...
let span = document.createElement('span');
span.style.color = '#ffffff';
// We set the element's span text to Please wait...
span.innerText = 'Done.';
// We add the span element to the document body.
document.body.append(span);
// We create an html img element and...
let br = document.createElement('br');
// We add the br element to the document body.
document.body.append(br);
// for each promise resolved...
for(let i = 0; i < myResponses.length; i++) {
// We check its returned object containing the resolverImg...
if(myResponses[i].resolverImg !== null) {
// We create an html img element and...
let img = document.createElement('img');
// We set the element's image source to the resolverImg url returned and..
img.src = myResponses[i].resolverImg;
// We add the img element to the document body.
document.body.append(img);
}
}
}).catch(err => console.error(err));
// The individual Promise.
// Accepts 5 arguments; image size, background color, foreground color, image file extension, image text.
async function getRandomImage(imgWidth, imgHeight, bgHexColor, fgHexColor, imgExt, imgText) {
// The Response interface of the Fetch API represents the response to a request.
// https://developer.mozilla/en-US/docs/Web/API/Response
// We initialize the image and status as null...
let myResolverImg = null;
let myResolverStatus = null;
// We use a Try/Catch block to check if the resolverImg exists...
try {
// We create a fetch async resolver...
let myResolver = await fetch(`https://dummyimage./${imgWidth}x${imgHeight}/${bgHexColor}/${fgHexColor}${imgExt}&text=${imgText}`);
// debug
// console.log(myResolver);
if(myResolver.ok) {
// if it exists, change it from null to a valid image url path.
myResolverImg = myResolver.url;
myResolverStatus = myResolver.status;
}
} catch (err) {
// if fetch network error...
console.error('Fetch network error.');
}
// Return js object containing image url OR, resolverImg REMAINS null as initially declared.
return {
resolverImg: myResolverImg,
resolverStatus: myResolverStatus
};
}