Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wait for for loop with async requests to finish in node.js?

I want to make multiple requests in node.js to get a couple of external API responses, to combine them into one array. I'm using a for loop to achieve this. Here's my code:

res.setHeader('Content-Type', 'application/json');
const sub = req.query.days_subtract;
const enddate = req.query.end_date; 

var array = [];

for (var i = 0; i < sub; i++) {
  request("https://api.nasa.gov/planetary/apod?date=" + subtractDate(enddate, i) + "&api_key=DEMO_KEY", function(error, response, body) {
    array.push(body); 
    // console.log(body);
  });
}
res.send(array);

but this piece of code returns [] all the time. I know it's because the for loop only starts these async requests, but it doesn't wait for them to finish. I tried to use async/await but that didn't work either. So how to wait for this loop to finish getting requests and to finish pushing them to the array so it can be shown to users?

like image 306
hamster121 Avatar asked Oct 09 '18 15:10

hamster121


Video Answer


2 Answers

For your use case, using await with Promise.all is probably the most performant way to go about it. Your code should look something like this:

res.setHeader('Content-Type', 'application/json');
const sub = req.query.days_subtract;
const enddate = req.query.end_date;

var promiseArray = [];

for (var i = 0; i < sub; i++) {
    promiseArray.push(new Promise((resolve, reject) => {
        request("https://api.nasa.gov/planetary/apod?date=" + subtractDate(enddate, i) + "&api_key=DEMO_KEY", function(error, response, body) {
        if (error) reject(error);
        else resolve(body)
    })
  }))
}
res.send(await Promise.all(promiseArray));
like image 73
Ayush Gupta Avatar answered Oct 03 '22 23:10

Ayush Gupta


As others have said, you should probably use Promise for your asynchronous code, and the async / await syntax is very legible.

However, you seem to prefer using callbacks. In that case, you could write your code this way :

res.setHeader('Content-Type', 'application/json');
const sub = req.query.days_subtract;
const enddate = req.query.end_date; 

var array = [];
var resultsCount = 0;

for (var i = 0; i < sub; i++) {
  request("https://api.nasa.gov/planetary/apod?date=" + subtractDate(enddate, i) + "&api_key=DEMO_KEY", function(error, response, body) {
    if (error) { res.status(500) }
    array[i] = body
    // console.log(body);
    resultCount++;
    if (resultCount === sub) {
      res.send(array);
    }
  });
}

Basically, the idea is to call the res.send method only once all requests have returned their result.

like image 28
Aymeric Bouzy aybbyk Avatar answered Oct 03 '22 22:10

Aymeric Bouzy aybbyk