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?
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)
);
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()
.
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.