I am using Angular + Firebase for a simple web app. I have this function:
private async uploadFile(id: number, filePath: string, name: string, input: HTMLInputElement) : Promise<string> {
const ext = filePath.split('.').pop();
const path = '/' + id + '/' + name + '.' + ext
const fileRef = ref(this.firebaseStorage, path);
await uploadBytesResumable(fileRef, input.files[0]);
let url: string = '';
await getDownloadURL(fileRef).then((result: string) => {
url = result;
});
console.log(url);
return url;
}
in which I want to upload a file in Firebase and return the string path (i.e. public url) of the image after it has been uploaded.
The problem is that the getDownloadURL(fileRef) returns a Promise and not a string, and I can't, for the life of me, figure out how to wait and unpack the promise to a string so that uploadFile can return a string value and not a promise!
I tried using the await keyword but the compiler still says it returns a Promise! What's the point then?
Edit: This is how I use uploadFile:
if (thumbnailStr != '') {
thumbnailStr = this.uploadFile(id, this.blogForm.get('thumbnail').value, 'thumbnail', thumbnailImg);
}
if (backgroundStr != '') {
backgroundStr = this.uploadFile(id, this.blogForm.get('background').value, 'background', backgroundImg);
}
console.log('url:', thumbnailStr);
const blog = {
'id': id,
'blogDate': datetime,
'heading': this.blogForm.get('heading').value,
'subHeading': this.blogForm.get('subHeading').value,
'blogDetail': this.blogForm.get('blogDetail').value,
'thumbnail': thumbnailStr,
'background': backgroundStr
};
this.blogs_service.addBlog(blog);
Edit #2: I figured it out. Making all functions asynchronous worked:
private async uploadFile(id: number, filePath: string, name: string, input: HTMLInputElement) : Promise<string> {
const ext = filePath.split('.').pop();
const path = '/' + id + '/' + name + '.' + ext
const fileRef = ref(this.firebaseStorage, path);
await uploadBytesResumable(fileRef, input.files[0]);
return await getDownloadURL(fileRef);
}
async addPost(thumbnailImg: HTMLInputElement, backgroundImg: HTMLInputElement) {
...
if (thumbnailStr != '') {
thumbnailStr = await this.uploadFile(id, this.blogForm.get('thumbnail').value, 'thumbnail', thumbnailImg);
}
if (backgroundStr != '') {
backgroundStr = await this.uploadFile(id, this.blogForm.get('background').value, 'background', backgroundImg);
}
...
P.S. I don't know why my question was marked as closed as I did not find the answer in the similar question but ok.
const url = await getDownloadURL(fileRef);should be all you needPromise<string>and not astring!so that uploadFile can return a string value and not a promise!That's impossible. The value doesn't exist yet, so the best you can do is return a promise fromuploadFile. Whatever code callsuploadFilewill need toawaitthat promise if it wants to know the valueWhy is it impossible to block and wait for the value to become availableJavascript is, for the most part, single threaded. If you could block, you would not want to because it would lock up the entire browser. There is technically a function that does a synchronous http request, butgetDownloadURLis (correctly) not written to use it. Since it doesn't use it, the code is asynchronous, and asynchronous code begets other asynchronous code. You can't take something that's asynchronous and make it synchronous in javascript.