简体   繁体   中英

Execute code only after a Javascript forEach/map

I have a forEach function that loops through an array of files, uploads the file to Firebase Storage and then after the upload, it stores the image reference link into a array defined before.

Process of each iteration:

  • Take file object and convert to Blob
  • Upload Blob onto Firebase
  • After Blob uploads, receive a callback which has the image reference of the upload
  • Store the image reference in a list

After the forEach , I use the list of image references for further processing. However, when I try and reference the list, it is usually empty because this code executes before any images upload (and references are not recieved). How can I use async/await with a Javascript forEach function where I can invoke my code to wait where it should expect a populated image reference list . I've already tried to find a solution on stackoverflow but hasn't helped toward my solution.

submitPost = async event => {

event.preventDefault();
const img_names = [];

this.state.files.forEach((ref_, index) => {
  ref_.current.getCroppedCanvas().toBlob(blob => {

    var uploadTask = this.storageRef
      .child("images/" + String(index))
      .put(blob);

    uploadTask.on(
      "state_changed",
      snapshot => {
        var progress =
          (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
        console.log("Upload is " + progress + "% done");
      },
      error => {
        console.log(error);
      },
      () => {
        img_names.push(uploadTask.snapshot.ref.toString());
      }
    );
  });
console.log(img_names) // empty here
});

You can achieve that functionality by using map instead of forEach . Convert your array into an Array of Promises. Then use that array inside a Promise.all() and await it.

const promisifyUpload = (storageRef, ref_, index) => {
  return new Promise((resolve, reject) => {
    ref_.current.getCroppedCanvas().toBlob(blob => {

      var uploadTask = storageRef
        .child("images/" + String(index))
        .put(blob);

      uploadTask.on(
        "state_changed",
        snapshot => {
          var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
          console.log("Upload is " + progress + "% done");
        },
        error => console.log(error),
        () => resolve(uploadTask.snapshot.ref.toString())
      );

    });
  });

};

const submitPost = async event => {

  event.preventDefault();

  const img_names = await Promise.all(
    this.state.files.map((ref_, index) => promisifyUpload(this.storageRef, ref_, index))
  ));

  console.log(image_names); // Should now be filled
});

Edit : I split it up into 2 functions to show isolate the "promisify" logic

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM