Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I return the accumulated results of multiple (parallel) asynchronous function calls in a loop?

Tags:

javascript

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.

like image 205
nnnnnn Avatar asked Jul 17 '16 23:07

nnnnnn


People also ask

How do I handle multiple async await?

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).

Do async functions run in parallel?

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).

Does every async always return promise?

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.

What is async loop?

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.


1 Answers

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.

like image 93
Oriol Avatar answered Oct 03 '22 16:10

Oriol