Reputation: 11
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
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
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
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
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
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