How to use promise in forEach loop of array to populate an object

I am running a forEach loop on an array and making two calls which return promises, and I want to populate an object say this.options, and then do other stuff with it. Right now I am running into the async issue if i use the following code sample and i get into the then function first.

$.when.apply($, someArray.map(function(item) {
    return $.ajax({...}).then(function(data){...});
})).then(function() {
    // all ajax calls done now
});

This is working code below, but it only works for the first element in the array, because I call the resulting function in the .then of the response. I want to do all the fetch first for all elements of the array and then call the resulting function to do something.

array.forEach(function(element) {
    return developer.getResources(element)
        .then((data) = > {
            name = data.items[0];
            return developer.getResourceContent(element, file);
        })
        .then((response) = > {
            fileContent = atob(response.content);
            self.files.push({
                fileName: fileName,
                fileType: fileType,
                content: fileContent
            });
            self.resultingFunction(self.files)
        }).catch ((error) = > {
            console.log('Error: ', error);
        })
});

How do i populate the self.files object after the forEach loop is complete, and then call the resulting function with the files object?

Answers:

Answer

Promise.all() will be helpful here:

var promises = [];

array.forEach(function(element) {
    promises.push(
        developer.getResources(element)
            .then((data) = > {
                name = data.items[0];
                return developer.getResourceContent(element, file);
            })
            .then((response) = > {
                fileContent = atob(response.content);
                self.files.push({
                    fileName: fileName,
                    fileType: fileType,
                    content: fileContent
                });
            }).catch ((error) = > {
                console.log('Error: ', error);
            })
    );
});

Promise.all(promises).then(() => 
    self.resultingFunction(self.files)
);

This starts the AJAX call for each of the items, adds the result of each call to self.files once the call is complete and calls self.resultingFunction() after all calls have been completed.

Edit: Simplified based on Yury Tarabanko's suggestions.

Answer

Just a slight variation of the accepted solution above would be:

var promises = array.map(function(element) {
      return developer.getResources(element)
          .then((data) = > {
              name = data.items[0];
              return developer.getResourceContent(element, file);
          })
          .then((response) = > {
              fileContent = atob(response.content);
              self.files.push({
                  fileName: fileName,
                  fileType: fileType,
                  content: fileContent
              });
          }).catch ((error) = > {
              console.log('Error: ', error);
          })
});

Promise.all(promises).then(() => 
    self.resultingFunction(self.files)
);

I used Array.map instead of Array.forEach, which means I don't need to create an empty array first, I just re-use the existing one.

Answer

You might look at this answer to a similar question for an excellent hint. The solution given there uses Array#reduce() to avoid having to accumulate all of the Promises before doing any of the work rather than using Promise.all().

Answer

The following code is simple understanding of sync using Promise.

let numArr = [1,2,3,4,5];
let nums=[];

let promiseList = new Promise(function(resolve,reject){
  setTimeout(()=>{
        numArr.forEach((val)=>{
        nums.push(val);
    });
    resolve(nums);
 },5000)
})


Promise.all([promiseList]).then((arrList)=>{
  arrList.forEach((array)=>{
    console.log("Array return from promiseList object ",array);    
  })

 });

Above example will hold array nums for 5 sec. and it will print on console after it release.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.