Caveat: I'm learning to work with JavaScript Promises and API calls, so I try to write the code in promise.then format as well as async / await, so I know how to use both.
I have a container that I am initially filling with images from 15 successive API calls; each call returns a single image. As scrolling happens, more API calls are made. I am able to make everything work with straightforward Promises as well as async / await.
I am trying to rewrite the API calls to make them concurrent rather than successive. My new code doesn't work - depending on what I've done, I get no result (and no error in my console) or a typeError of undefined. I don't know what I am doing wrong.
This is the code that is working - in both formats (not including the page load code and intersectionObserver)
promises only
const getImage = function () {
fetch("https://api.api-ninjas.com/v1/randomimage", {
method: "GET",
headers: {
"X-API-Key": "###",
Accept: "image/jpg",
},
})
.then((response) => {
if (!response.ok) throw new Error("Network failure");
return response.blob();
})
.then((blob) => {
const img = document.createElement("img");
img.src = URL.createObjectURL(blob);
container.append(img);
})
.catch((err) => console.error(`${err.message}`));
};
async / await
const getImage = async function () {
try {
const response = await fetch("https://api.api-ninjas.com/v1/randomimage/", {
method: "GET",
headers: {
"X-API-Key": "###",
Accept: "image/jpg",
},
});
if (!response.ok)
throw new Error(`Network failure! Status: ${response.status}`);
const data = await response.blob();
const img = document.createElement("img");
img.src = URL.createObjectURL(data);
container.append(img);
} catch {
(err) => console.error(`${err.message}`);
}
};
This is what I am trying for concurrent calls; I am calling the function after disabling all my other page load code just to see if it's working at all. Nothing loads on my page and I get no error or TypeError in my console.
const getImage = function () {
fetch("https://api.api-ninjas.com/v1/randomimage", {
method: "GET",
headers: {
"X-API-Key": "###",
Accept: "image/jpg",
},
});
};
const firstImages = async function () {
try {
const res = await Promise.all([
getImage(),
getImage(),
getImage(),
getImage(),
getImage(),
getImage(),
getImage(),
getImage(),
getImage(),
getImage(),
getImage(),
getImage(),
getImage(),
getImage(),
getImage(),
]);
const data = await Promise.all(res.forEach((r) => r.blob()));
console.log(data);
data.forEach((d) => {
const img = document.createElement("img");
img.src = URL.createObjectURL(d);
container.append(img);
});
} catch {
(err) => console.error(`${err.message}`);
}
};
firstImages();
Let me try to help you out a bit. Also added a small loop so you can decide how many images you actually want to bring out. See comments in code as well:
const getImage = function () {
// Firstly, as Andy wrote in comments, return the fetch
return fetch("https://api.api-ninjas.com/v1/randomimage", {
method: "GET",
headers: {
"X-API-Key": "###",
Accept: "image/jpg",
},
});
};
const firstImages = async function (numberOfImages = 1) {
try {
const fetchArr = [];
let i = 0;
while (i <= numberOfImages) {
fetchArr.push(getImage());
i++;
}
const res = await Promise.all(fetchArr);
// As was pointed out by another comment, use map here, as it will return an array that the Promise.all can iterate over.
const data = await Promise.all(res.map((r) => r.blob()));
data.forEach((d) => {
const img = document.createElement("img");
img.src = URL.createObjectURL(d);
container.append(img);
});
} catch {
// Probably best (as Keith commented) to just pass the error object to the console.error. It will print a few extra things that are normally noteworthy when tragedy strikes
(err) => console.error(err);
}
};
firstImages(15);
Good luck!!