I have a function foo
which makes multiple (parallel) asynchronous calls in a loop. I need to somehow wait until the results of all of the calls are available. How can I return the full results from foo
, or otherwise trigger some processing after all of the data is available?
I tried adding each result to an array, but then the array isn't populated until after the point where I need to use it.
function foo() {
var results = [];
for (var i = 0; i < 10; i++) {
someAsyncFunction({someParam:i}, function callback(data) {
results.push(data);
});
}
return results;
}
var result = foo(); // It always ends up being an empty array at this point.
Note: this question is deliberately generic along the lines of the existing generic "How do I return the response from an asynchronous call?" question. That question has some excellent answers, but doesn't cover multiple async calls. There are some other questions that mention multiple calls, but I couldn't find any loop-based ones, and some only had jQuery answers, etc. I'm hoping here for some generic techniques that don't depend on a particular library.
In order to run multiple async/await calls in parallel, all we need to do is add the calls to an array, and then pass that array as an argument to Promise. all() . Promise. all() will wait for all the provided async calls to be resolved before it carries on(see Conclusion for caveat).
Asynchronous operations in parallelThe method async. parallel() is used to run multiple asynchronous operations in parallel. The first argument to async. parallel() is a collection of the asynchronous functions to run (an array, object or other iterable).
Async functions always return a promise. If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise. Note: Even though the return value of an async function behaves as if it's wrapped in a Promise.resolve , they are not equivalent.
For loops. Combining async with a for (or a for...of ) loop is possibly the most straightforward option when performing asynchronous operations over array elements. Using await inside a for loop will cause the code to stop and wait for the asynchronous operation to complete before continuing.
Use promises. Precisely, Promise.all
was designed for this.
It takes an array (or iterable) of promises, and returns a new promise which is resolved when all the promises of the array have been resolved. Otherwise, it rejects when any promise of the array rejects.
function someAsyncFunction(data, resolve, reject) {
setTimeout(function() {
if(Math.random() < .05) {
// Suppose something failed
reject('Error while processing ' + data.someParam);
} else {
// Suppose the current async work completed succesfully
resolve(data.someParam);
}
}, Math.random() * 1000);
}
function foo() {
// Create an array of promises
var promises = [];
for (var i = 0; i < 10; i++) {
// Fill the array with promises which initiate some async work
promises.push(new Promise(function(resolve, reject) {
someAsyncFunction({someParam:i}, resolve, reject);
}));
}
// Return a Promise.all promise of the array
return Promise.all(promises);
}
var result = foo().then(function(results) {
console.log('All async calls completed successfully:');
console.log(' --> ', JSON.stringify(results));
}, function(reason) {
console.log('Some async call failed:');
console.log(' --> ', reason);
});
Note that the results will be given according to the order of the array of promises, not in the order that the promises were resolved in.
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