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

upload task getDownloadUrl() after completion


I need this general purpose utility method that accepts the file object and return me the url of the file after uploading, but some how I am getting a promise instead of the download URL.

I have tried all approached, i need ES6 async/await solution.

export const uploadFile = (file) => {
  let uploadTask = storage.ref(`products/${Date.now()}.${file.name.split('.').pop()}`).put(file);
  uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED, {
    'complete': () => {
      uploadTask.snapshot.ref.getDownloadURL().then((d) => {
        return d
      })
    }
  });
}

Solution

  • As explained in the doc, if you call then() on a UploadTask, you will get an object which "behaves like a Promise, and resolves with its snapshot data when the upload completes".

    Therefore the following should do the trick.

    export const uploadFile = (file) => {
      let uploadTask = storage.ref(`products/${Date.now()}.${file.name.split('.').pop()}`).put(file);
      return uploadTask.
        then(snapshot => {
          return snapshot.ref.getDownloadURL();
        })
        .then((url) => {
          return url
        });
    }
    

    Update following your comment:

    You mention in the comments that you call the function as follows:

    let files = state.images; 
    for (let i = 0; i < e.target.files.length; i++) { 
       files = files.concat(e.target.files[i]); 
       let url = uploadFile(files[i])
       console.log(url)
    }
    

    However, the uploadFile() function is asynchronous and indeed, as a consequence, it returns a Promise. You should take that into account when calling it. For example, with a loop, you could call it as follows:

    const promises = [];
    let files = state.images; 
    for (let i = 0; i < e.target.files.length; i++) { 
       files = files.concat(e.target.files[i]); 
       promises.push(uploadFile(files[i]));
    }
    Promise.all(promises)
     .then(urlsArray => {
        urlsArray.forEach(url => {
            console.log(url);
        })
      })