Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to do async await on a forEach function [duplicate]

I'm a beginner in async await and promises. I read few articles and watch few tutorial videos but I am still not able to understand it completely. So I have a code that I'm working on right now

}).then(function() {
  var responseArray = []
  [url1,url2,url3,url4].forEach((url)=>{
      makeRequest(url)
  }).then((response)=>{
      responseArray.push(response)
  })
  return responseArray
})

So as expected the responseArray is returned empty. I need to make it wait until all the responses from each makerequest(url) is pushed to the responseArray.
This is my attempt

}).then(function() {
      var responseArray = []
      [url1,url2,url3,url4].forEach((url)=>{
          async makeRequest(url)
      }).then((response)=>{
          await responseArray.push(response)
      })
      return responseArray
    })

Can anyone help me fix this one?

like image 882
anoop chandran Avatar asked May 14 '18 10:05

anoop chandran


People also ask

Can you use async await in forEach?

forEach is not designed for asynchronous code. (It was not suitable for promises, and it is not suitable for async-await.) For example, the following forEach loop might not do what it appears to do: const players = await this.

Can you await in a for loop?

You need to place the loop in an async function, then you can use await and the loop stops the iteration until the promise we're awaiting resolves. You could also use while or do.. while or for loops too with this same structure. But you can't await with Array.

Can one async function have multiple awaits?

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

What happens if you use await inside a loop and what are the alternatives?

If you use await in a map , map will always return an array of promises. This is because asynchronous functions always return promises. Since map always return promises (if you use await ), you have to wait for the array of promises to get resolved. You can do this with await Promise.


2 Answers

You need to map the requests to an array of promises then use Promise.all:

.then(async () => {
  const responseArray = await Promise.all(
    [url1, url2, url3, url4].map(makeRequest)
  );
})

This will execute all the requests in parallel (which is generally what you want unless you want to limit the bandwidth etc).

If you want to execute them sequentially, there's a huge discussion on the best approach.

like image 140
Roy Wang Avatar answered Sep 20 '22 16:09

Roy Wang


You cannot wait for all the promises to be resolved if you use forEach. Use for .. of instead:

}).then(async function() {
    var arr = ['url1', 'url2', 'url3', 'url4'];
    var responseArray = []; 
    for (url of arr) {
        cont response = await makeRequest(url);
        responseArray.push(response);
    }
    return responseArray;
});

Or, for a better performance, you can use Promise.all to launch all your requests in parallel:

}).then(async function() {
    var arr = ['url1', 'url2', 'url3', 'url4'];
    var responseArray = await Promise.all(arr.map(function(url) {
        return makeRequest(url);
    }));
    return responseArray;
});
like image 25
Faly Avatar answered Sep 17 '22 16:09

Faly