Reputation: 1
I'm pretty new to javascript and I'm having trouble with async/await and promises. I'm trying to upload an array of images to firebase asynchronously so I get the URLs back for the next step. The following is the upload function.
const uploadImage = async (file) => {
console.log("starting...");
const storageRef = firebase.storage().ref("forum/" + file[1]);
return new Promise((resolve, reject) => {
fetch(file[0])
.then(async (res) => {
console.log("res to blob");
return await res.blob();
})
.then(async (blob) => {
blob.name = file[1];
console.log("Starting to put file...", blob);
await storageRef.put(blob).then(async () => {
const url = await storageRef.getDownloadURL();
urlArray.push(url);
console.log(url);
!url ? resolve("got url!") : reject("it broke");
});
});
console.log("done!");
});
};
const uploadArray = async (imageArray) => {
return await Promise.all(
imageArray.map((image) => uploadImage(image))
);
};
uploadArray(project.images).then((urls) => {
urls.forEach((element) => {
console.log(element);
});
});
This is the console every time uploadArray() is called.
starting...
done!
starting...
done!
res to blob
Starting to put file... Blob {name: "IMG_3851.JPG", size: 1417851, type: "image/jpeg"}
Starting to put file... Blob {name: "IMG_3852.JPG", size: 2391056, type: "image/png"}
https://firebasestorage.googleapis.com/... (Link to firebase)
Uncaught (in promise) it broke```
https://firebasestorage.googleapis.com/... (Link to firebase)
But I want the console to log the statements in this order instead.
starting
res to blob
Starting to put file... Blob {name: "IMG_3851.JPG", size: 1417851, type: "image/jpeg"}
https://firebasestorage.googleapis.com/... (Link to firebase)
done!
starting
res to blob
Starting to put file... Blob {name: "IMG_3852.JPG", size: 2391056, type: "image/png"}
https://firebasestorage.googleapis.com/... (Link to firebase)
done!
Upvotes: 0
Views: 353
Reputation: 154
Couple tidbits about JS and async/await:
await
inside it - otherwise you might get undefined behavior when errors occurfetch
, you're console.log("done!");
should go after the line where you resolve/reject. It's not so it gets executed immediately, that's why your seeing them printed right after "starting"
.then
with an await
. Avoiding "callback hell" is very important in JS when it comes to code clarity. Sometimes it's not possible to get around using new Promise()
, but if it can be avoided, it should beLike @Evert's answer, removing callbacks and using proper awaits will likely fix your ordering issues.
It would also be a good idea to add a try catch around all the API calls so that you don't get an unhandled promise exception. It can be added to the uploadImage
method, or to where you call Promise.all
, whatever works best for your use case.
const uploadImage = async (file) => {
try {
console.log("starting...");
const storageRef = firebase.storage().ref("forum/" + file[1]);
const res = await fetch(file[0]);
console.log("res to blob");
const blob = await res.blob();
blob.name = file[1];
console.log("Starting to put file...", blob);
await storageRef.put(blob);
const url = await storageRef.getDownloadURL();
urlArray.push(url);
console.log(url);
if (!url) throw new Error("it broke");
console.log("done!");
} catch (err) {
console.error(err);
}
};
Upvotes: 0
Reputation: 99523
The way you are handling promises is a bit strange, and has the new Promise
constructor anti-pattern. I rewrote the messy parts here, and I suspect this will solve your ordering issue:
const uploadImage = async (file) => {
console.log("starting...");
const storageRef = firebase.storage().ref("forum/" + file[1]);
const res = await fetch(file[0]);
const blob = await res.blob();
blob.name = file[1];
console.log("Starting to put file...", blob);
await storageRef.put(blob);
const url = await storageRef.getDownloadURL();
urlArray.push(url);
console.log(url);
if (url) {
return "got url";
}
throw "it broke";
}
The snippet above mostly does what you wrote, but all the unnecessary then's removed. It should be a lot clearer. It's very worthwhile fully learning promises and async/await before you proceed. The code you shared feels very trial and error.
Upvotes: 1