0

I can't seem to find how to solve my problem.

I am using socket to get live data, there is a .on() event which then executes another function async to get api data.

socket.on('data', (data) => { // listen to live events - event 1, 2, 3, 4, 5
  getAPIData(data);
});

async function getAPIData(data){
 const {symbol} = data;
 axios.get(`https://api.nasa.gov/planetary/apod?name=${symbol}`).then((newData)=>{
  console.log(newData); // console events  - 1,3,5,2,4 - I need this to be in the right order as they come in
 })
};

Socket.on() get multiple events per second and I need each for calculations. my problem now is that console.log(newData) is not logging in order as they come in because its promise based async.

and I really need the exact order they come in, how to do this in JavaScript nodejs.

7
  • Does this answer your question? How do I execute four async functions in order? Commented Mar 7, 2022 at 9:20
  • There's no reason for getAPIData to be async. You're using then not await. Commented Mar 7, 2022 at 9:20
  • @EzioMercer - I think probably not, if we look closely at what the OP is trying to do. Commented Mar 7, 2022 at 9:22
  • Are you sure you want a reasonable thing here, or do you just want your console logs to be "ordered" because it looks neat? I would rather have things be carried out as fast as possible, instead of introducing artificial waiting times so the console output looks better. Commented Mar 7, 2022 at 9:22
  • Thank you for the answer, I made a mistake of using a wrong example. I have added my actual code now. Commented Mar 7, 2022 at 10:53

1 Answer 1

1

You can serialize the calls to axios and the logging of the results like this (but keep reading, we can also overlap the axios calls while still doing the output in order):

let queueLength = 0;
let sequencer = Promise.resolve();
function getAPIData(data){
    const {symbol} = data;
    ++queueLength;
    console.log("Added work item, queue length: " + queueLength);
    sequencer = sequencer
        .then(() => axios.get(`https://api.nasa.gov/planetary/apod?name=${symbol}`))
        .then((newData) => {
            console.log(newData);
        })
        .catch(error => {
            // ...handle/report error...
        })
        .finally(() => {
            --queueLength;
            console.log("Completed work item, queue length: " + queueLength);
        });
}

Live Example:

const rnd = (max) => Math.floor(Math.random() * max);

// Fake a sequence of socket.io events
for (let i = 0; i < 5; ++i) {
    setTimeout(() => {
        getAPIData({symbol: i});
    }, 100 * (i + 1));
}

// Fake axios
const axios = {
    get(url) {
        console.log(`Start ${url}`);
        const [, num] = /(\d+)$/.exec(url);
        return new Promise(resolve => setTimeout(() => {
            console.log(`End ${url}`);
            resolve(num);
        }, rnd(800)));
    },
};

let queueLength = 0;
let sequencer = Promise.resolve();
function getAPIData(data){
    const {symbol} = data;
    ++queueLength;
    console.log("Added work item, queue length: " + queueLength);
    sequencer = sequencer
        .then(() => axios.get(`https://api.nasa.gov/planetary/apod?name=${symbol}`))
        .then((newData) => {
            console.log(newData);
        })
        .catch(error => {
            // ...handle/report error...
        })
        .finally(() => {
            --queueLength;
            console.log("Completed work item, queue length: " + queueLength);
        });
}
.as-console-wrapper {
    max-height: 100% !important;
}

Here's how that works:

  1. We start with a fulfilled promise in sequencer.
  2. Each time getAPIData is called, it waits for the previous promise to be settled before doing the axios call
  3. We assign the promise from the promise chain as the new value of sequencer so the next pass waits on it.

That does mean that each call to axios won't be done until the previous one finishes; there will never be any overlap. But if you just want the results in order, you can overlap the calls to axios, like this:

let queueLength = 0;
let sequencer = Promise.resolve();
function getAPIData(data){
    const {symbol} = data;
    ++queueLength;
    console.log("Added work item, queue length: " + queueLength);
    sequencer = Promise.all([
            sequencer,
            axios.get(`https://api.nasa.gov/planetary/apod?name=${symbol}`)
        ])
        .then(([, newData]) => { // Note the destructuring on this line
            console.log(newData);
        })
        .catch(error => {
            // ...handle/report error...
        })
        .finally(() => {
            --queueLength;
            console.log("Finished work item, queue length: " + queueLength);
        });
}

That way, the axios calls can overlap, but we still do the logging in order.

Live Example:

const rnd = (max) => Math.floor(Math.random() * max);

// Fake a sequence of socket.io events
for (let i = 0; i < 5; ++i) {
    setTimeout(() => {
        getAPIData({symbol: i});
    }, 100 * (i + 1));
}

// Fake axios
const axios = {
    get(url) {
        console.log(`Start ${url}`);
        const [, num] = /(\d+)$/.exec(url);
        return new Promise(resolve => setTimeout(() => {
            console.log(`End ${url}`);
            resolve(num);
        }, rnd(800)));
    },
};

let queueLength = 0;
let sequencer = Promise.resolve();
function getAPIData(data){
    const {symbol} = data;
    ++queueLength;
    console.log("Added work item, queue length: " + queueLength);
    sequencer = Promise.all([
            sequencer,
            axios.get(`https://api.nasa.gov/planetary/apod?name=${symbol}`)
        ])
        .then(([, newData]) => { // Note the destructuring on this line
            console.log(newData);
        })
        .catch(error => {
            // ...handle/report error...
        })
        .finally(() => {
            --queueLength;
            console.log("Finished work item, queue length: " + queueLength);
        });
}
.as-console-wrapper {
    max-height: 100% !important;
}

Example output of that:

Added work item, queue length: 1
Start https://api.nasa.gov/planetary/apod?name=0
Added work item, queue length: 2
Start https://api.nasa.gov/planetary/apod?name=1
Added work item, queue length: 3
Start https://api.nasa.gov/planetary/apod?name=2
End https://api.nasa.gov/planetary/apod?name=2
Added work item, queue length: 4
Start https://api.nasa.gov/planetary/apod?name=3
End https://api.nasa.gov/planetary/apod?name=0
0
Finished work item, queue length: 3
Added work item, queue length: 4
Start https://api.nasa.gov/planetary/apod?name=4
End https://api.nasa.gov/planetary/apod?name=3
End https://api.nasa.gov/planetary/apod?name=1
1
Finished work item, queue length: 3
2
Finished work item, queue length: 2
3
Finished work item, queue length: 1
End https://api.nasa.gov/planetary/apod?name=4
4
Finished work item, queue length: 0

Notice that even though the call for name=2 finished before the call for name=0, 0 was logged before 2.

Sign up to request clarification or add additional context in comments.

7 Comments

@MaygaFatmawati - Explained it differently how? (I figured the code was just an example. But the solution above applies generally, not just to this example.)
Thank you for the answer, I made a mistake of using a wrong example. I have added my actual code now.
@MaygaFatmawati - I don't see any fundamental difference, in both cases you're doing a call to an async function. The above seems like it applies just fine. But separately: It's not okay on Stack Overflow to edit the question so that it makes existing answers look like they're not related to the question. We should roll back the edit. If you can't apply the above to your real code, that might be a different question, but I think you probably can apply it. Give it a try, and if you run into a specific problem doing so, post a question about that new problem.
Ok, I am testing your example on my code now, is there a way to see the que of waiting functions. if this works the way I need, I need to know if we can handle the amount of functions executing, because its "never" ending
This does indeed what I need. thank you very much for the help. One thing I don't understand is the .then([, newData]) destructuring.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.