Funny Dog
Funny Dog

Reputation: 11

Wait a result for a API inside a loop

I'm new to Node and I tried to understand promises, but it's kinda complicated. I'm trying to call an API many times and then return my result. But my route sends a response first.

I want to return my response only after I finish the loop

data = {}
req.body.words.forEach(function (word) {

    newsapi.v2.everything({
        q: word,
        domains: req.body.domains.join(', '),
        sort_by: 'relevancy'
        })
        .then(response => {

            data[word]=response;
        })
    });

    return res.json(data);

It returns a empty array.

Upvotes: 0

Views: 2834

Answers (5)

Zaid shaikh
Zaid shaikh

Reputation: 21

For-each loop can't wait for async-await. so, instead of for-each, you need to use for loop and do your code inside of for loop.

for(let i = 0; i < arr.length; i++){
 await apicall();
}

Upvotes: 0

ziny
ziny

Reputation: 11

You can use "for-async" npm:

   var forAsync = require("for-async");

    data = {}
     forAsync(req.body.words, function (word, i) {
          return new Promise(function (next) {

            newsapi.v2.everything({
              q: word,
              domains: req.body.domains.join(', '),
              sort_by: 'relevancy'
              })
              .then(response => {
                data[word]=response;
                next(); //go to the next iteration
            });

          });
      }).then(() => {
         console.log("Loop finished");
         return res.json(data);
      });

Upvotes: 0

deathstroke
deathstroke

Reputation: 603

let promisesToAwait = [];
let words = req.body.words;
for (let j = 0; j < words.length; j++) {
   promisesToAwait.push(await this.loopThruAllWords(words[j], req.body.domains.join(', ')));
}
let allResponses = await Promise.all(promisesToAwait1);

async loopThruAllWords(word, domains){
let response = await newsapi.v2.everything({
    q: word,
    domains: domains,
    sort_by: 'relevancy'
    });
return Promise.resolve(response);
}

Upvotes: 0

Abhay Maurya
Abhay Maurya

Reputation: 12277

That is because requests are asynchronus, you need a work around in order to hold on to the result until all requests are completed, you can achieve that by a counter like so:

data = {}
let count = 0;
req.body.words.forEach(function (word) {
    count++;
    return newsapi.v2.everything({
        q: word,
        domains: req.body.domains.join(', '),
        sort_by: 'relevancy'
        })
        .then(response => {
            data[word]=response;
            //return only if all the entries are processed
            if (count === req.body.words.length) {
                return res.json(data);
            }
        });
    });

Upvotes: 0

Aritra Chakraborty
Aritra Chakraborty

Reputation: 12542

Your loop is synchronous it is initiating the async calls but never waits for them. Either you can use Promise.all to get all the result parallely. Or can use async-await in parallel or serial manner.

data = {}
const promises = [];
req.body.words.forEach(function (word) {

    const promise = newsapi.v2.everything({
        q: word,
        domains: req.body.domains.join(', '),
        sort_by: 'relevancy'
    })
        .then(response => {

            data[word] = response;
        })
    promises.push(promise);
});

Promise.all(promises)
.then(()=>{
    res.send(data);
})

I have made a medium post for the exact same problem: https://medium.com/trappedpanda/loops-asynchronous-functions-and-returning-collective-results-in-node-js-b7566285fb74

Upvotes: 2

Related Questions