Reputation: 77
this is the code from my route:
const hotspots = await Hotspot.find({user: req.user._id});
if(!hotspots) return res.render("hotspot");
let hotspotData = [];
let rewards = [];
function getApiData(){
return new Promise((resolve,reject)=>{
let error = false;
for (let hotspot of hotspots){
axios.get(`https://api.helium.io/v1/hotspots/${hotspot.hotspot}`)
.then((resp)=>hotspotData.push(resp.data));
axios.get(`https://api.helium.io/v1/hotspots/${hotspot.hotspot}/rewards/sum`)
.then((resp)=> {
console.log("first console log",resp.data.data.total)
rewards.push(resp.data.data.total) ;
console.log("Data gained from axios",resp.data.data.total);
})
}
if(!error) resolve();
else reject("Something went wrong");
})
}
getApiData().then(()=> {
console.log(hotspotData);
console.log(rewards);
res.render("hotspot",{hotspots: hotspotData, rewards: rewards});
});
Everything else is fine, but when I'm logging hotspotData
and rewards
, I'm getting an empty array but as you can see I've already pushed the data I got from APIs to those arrays respectively. But sti;; I'm getting empty array. Please help me. I have logged the API data and yes it's sending the correct data but I don't know why that data does not get pushed to the arrays.
Edit: This is the output which suggests my code is not getting executed in the way I want it to:
Upvotes: 0
Views: 105
Reputation: 859
What happens here is that the code that sends back the response is executed before the axios responses arrive:
then()
function.resolve()
d (watch out there's no code to handle a rejected response).for
loop ends, it doesn't wait
for the axios
promises to return, it just triggers the requests and
continue. The code block after they return will be run in another moment.If you want to solve this, one thing you could do is to use async/await everywhere, and make the calls sequentially, something like this:
const hotspots = await Hotspot.find(...);
function async getApiData() {
let hotspotData = [];
let rewards = [];
for loop {
hotspot = await axios.get(hotspot)
reward = await axios.get(reward)
...
// add both to the arrays
}
return { hotspotData, rewards }
}
const { hotspotData, rewards } = await getApiData();
console.log(hotspotData);
console.log(rewards);
res.render("hotspot",{hotspots: hotspotData, rewards: rewards});
Note: the code above is more pseudo-code than real javascript ok?
I think this could be an interesting read: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await
Also, notice all the axios calls seem to be independent from each other, so perhaps you can run them asynchronously, and wait for all promises to be resolved to continue. Check this out for more info about it: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all (make sure it works sequentially, first)
I think it should be something like an array of promises (one per hotspot and reward in the for
loop), then returning something like:
return Promise.all([promise1, promise2, promise3]);
Upvotes: 1