Zain763
Zain763

Reputation: 77

How do I execute these 2 different blocks of code in a sequence in JavaScript?

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:

output

Upvotes: 0

Views: 105

Answers (1)

germanio
germanio

Reputation: 859

What happens here is that the code that sends back the response is executed before the axios responses arrive:

  • First, a call to a database (is that correct?) using a async/await approach.
  • Then you define a function that returns a Promise and call it processing the response in the then() function.
  • That piece of code is executed when the Promise is resolve()d (watch out there's no code to handle a rejected response).
  • Now the promise is resolved once the 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

Related Questions