how to wait for promise resolve in array.map method?

promise.map es6
async/await array#map
promise.all map
javascript wait for map to finish
await array of promises
promise.map is not a function
async.map example
promise.all empty array

I want to upload photos to firebase storage.

In the state of React component I have array with photos. Photos are files that user browse through file input. Photos has property .needUpload to true, if file need to upload to storage.

Here is upload function:

uploadPhotos = () => {
    let photosToSave = []
    if (this.state.photos.length) {
      photosToSave = this.state.photos
        .filter(photo => photo.needUpload && true)
        .map(photo => {
          const extensionPattern = /(?:\.([^.]+))?$/
          const fileName = photo.value.name
          const fileExtension = extensionPattern.exec(fileName)[1]
          const newFileName = new Date().getTime()
          const fileLocation = storageRef.child('estateObjects/' + newFileName + '.' + fileExtension)

          return new Promise(resolve => {
            fileLocation.put(photo.value).on(
              firebase.storage.TaskEvent.STATE_CHANGED,
              snapshot => {
                //let progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
              },
              null,
              () => {
                fileLocation.getDownloadURL().then(url => {
                  resolve({ url: url, file: newFileName + '.' + fileExtension })
                })
              }
            )
          })
        })
      return Promise.all(photosToSave).then(response => {
        return response
      })
    } else return Promise.all(photosToSave).then(response => [])
  }

The main problem is that when upload starts, it (patiently) waiting, I guess for upload first 2-3 files, then in 'resolve' array I'm getting duplicated array elements. So something working wrong, but I cant understand what...

maybe problem is with new file name?? When file renames new Date.getTime() returns same time for few files, cause they where uploaded at the same time?

the map loop runs very quickly, so the time won't change between iterations

So, I suggest you use the index to guarantee filename uniqueness

uploadPhotos = () => {
  let photosToSave = [];

  if (this.state.photos.length) {
    photosToSave = this.state.photos.filter(photo => photo.needUpload && true).map((photo, index) => {
      const extensionPattern = /(?:\.([^.]+))?$/;
      const fileName = photo.value.name;
      const fileExtension = extensionPattern.exec(fileName)[1];
      const newFileName = `${new Date().getTime()}_${index}`;
      const fileLocation = storageRef.child('estateObjects/' + newFileName + '.' + fileExtension);
      return new Promise(resolve => {
        fileLocation.put(photo.value).on(firebase.storage.TaskEvent.STATE_CHANGED, snapshot => {//let progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
        }, null, () => {
          fileLocation.getDownloadURL().then(url => {
            resolve({
              url: url,
              file: newFileName + '.' + fileExtension
            });
          });
        });
      });
    });
    return Promise.all(photosToSave).then(response => {
      return response;
    });
  } else return Promise.all(photosToSave).then(response => []);
}

Use async await with Array.map, all(iterable) method returns a promise that resolves when all of the promises in the iterable argument have resolved, or rejects with the reason of� So since you passed await an array (of Promise objects) here instead of a Promise, the value returned by await is simply that array, which is of type Promise<number>[]. What you need to do here is call Promise.all on the array returned by map in order to convert it to a single Promise before await ing it.

I think an alternative to add a synchronous method on newFileName can work.

var time = ''; //Global variable
function getTime() {
   if(new Date().getTime() === time){return getTime()}
   else time = new Date().getTime();
   return time;
}

Node.js — How to Run an Asynchronous Function in Array.map(), map() is to return a promise for each item which then resolve outside the map function Duration: 10:22 Posted: 25-Jan-2018 The Promise.resolve() method returns a Promise object that is resolved with a given value. If the value is a promise, that promise is returned; if the value is a thenable (i.e. has a "then" method), the returned promise will "follow" that thenable, adopting its eventual state; otherwise the returned promise will be fulfilled with the value. This function flattens nested layers of promise-like

I ran this on console and here is result, guessing that whould be the problem.

 [...Array(7).keys()].map(v=> console.log(new Date().getTime()))

VM676:2 1572510011727
VM676:5 1572510011728

There is a Zero-dependency library uuid, you can use to make sure using unique filenames here

npm install uuid

const uuidv1 = require('uuid/v1');
uuidv1(); // ⇨ '2c5ea4c0-4067-11e9-8bad-9b1deb4d3b7d'

Array.map() + async/await - DEV, map function will return an Array of unresolved promises. Therefore, outside of the Array.map, we have to wait for all the promises to be resolved� The main thing to notice is the use of Promise.all(), which resolves when all its promises are resolved. list.map() returns a list of promises, so in result we’ll get the value when everything we ran is resolved. Remember, we must wrap any code that calls await in an async function.

Await promise.all: How to use async/await with map and Promise.all , I found myself stuck on using the map function with async and await. returns a resolved promise with all of the inner promises as resolved. The main point is that Promise.all() turns an array of promises into a single� Return a Promise for Each Array Item. An approach to perform async actions in array.map() is to return a promise for each item which then resolve outside the map function. Because map won’t wait for the promise to resolve, it’ll return a pending promise. If you’d console log the resulting array from map, it looks like this:

Making array iteration easy when using async/await, Let's start with the Array#map() method: as it will return a single Promise that gets resolved when all the promises in users have resolved. This happens because after making a call to getResult method, it in turns calls the getPromise method which gets resolved only after 2000 ms. getResult method doesn’t wait since it doesn’t returns a promise. So, if you return a promise from getResult method it can then be used to wait for the Promise to get resolved. Let’s try it.

Promise.all(), The Promise.all() method takes an iterable of promises as an input, and returns This returned promise will resolve when all of the input's promises have it does not wait and will reject immediately upon any of the input promises rejecting. The returned promise is fulfilled with an array containing all the� The Promise.allSettled() method returns a promise that resolves after all of the given promises have either fulfilled or rejected, with an array of objects that each describes the outcome of each promise.

Comments
  • yes, the map loop runs very quickly, so the time won't change
  • So what's the best way to rename file with unique name?
  • new Date().getTime() is giving same time, it's running quickly
  • you could .map((photo, index) => and use the index to ensure unique filenames
  • const newFileName = `${new Date().getTime()}_${index}`;