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?
JavaScript Promises forEach with promises It is possible to effectively apply a function ( cb ) which returns a promise to each element of an array, with each element waiting to be processed until the previous element is processed.
JavaScript's Array#forEach() function lets you iterate over an array, but not over an object. But you can iterate over a JavaScript object using forEach() if you transform the object into an array first, using Object. keys() , Object. values() , or Object.
To use Javascript promises in a for loop, use async / await . This waits for each promiseAction to complete before continuing to the next iteration in the loop. In this guide, you learn how async/await works and how it solves the problem of using promises in for loops.
The forEach method is also used to loop through arrays, but it uses a function differently than the classic "for loop". The forEach method passes a callback function for each element of an array together with the following parameters: Current Value (required) - The value of the current array element.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With