Search code examples
javascriptfirebasegoogle-cloud-platformgoogle-cloud-storagefirebase-storage

How to upload images to firebase storage and wait for URLs to return before continuing


I'm trying to create a "Create Post" form where the user can input text, as well as input images.

uploadImages() {
    const files = document.querySelector('#imagesInput').files;
    files.forEach(image => {
        console.log("uploading", image.name)
        const name = (+new Date()) + '-' + image.name;
        const task = fb.storage.child(name).put(image, {contentType: image.type});
        task.then(snapshot => {
            snapshot.ref.getDownloadURL().then(url => {
                console.log(url);
            })
        })
    });
}

The image upload process needs to happen first, and I need to return all the URLs (as an array) before the post is created in the database.

imageURLs = this.uploadImages(); // <-- Wait for this to complete and return the image URIs
this.createPost("Hello, world!", imageURLs) // <-- then do this

Solution

  • Since you call the asynchronous getDownloadURL() method a variable number of times (i.e. unknown at the time of coding), you need to use Promise.all() as follows:

    uploadImages() {
        const files = document.querySelector('#imagesInput').files;
    
        const promises = [];
        files.forEach(image => {
            console.log("uploading", image.name)
            const name = (+new Date()) + '-' + image.name;
            const task = fb.storage.child(name).put(image, { contentType: image.type });
            promises.push(task);
        });
    
        return Promise.all(promises)
            .then(snapshotsArray => {
                // snapshotsArray is an array with a variable number of elements
                // You again need to use Promise.all
                const promises = [];
                snapshotsArray.forEach(snapshot => {
                    promises.push(snapshot.ref.getDownloadURL());
                })
                return Promise.all(promises);
            });
    }
    

    The uploadImages() function is asynchronous and returns a Promise (since Promise.all() and then() return Promises): you therefore need to call it by using then(), as follows:

    this.uploadImages()
    .then(imageURLs => {
       this.createPost("Hello, world!", imageURLs) 
    })