parsecer
parsecer

Reputation: 5106

Javascript: print message after all http requests have been send, asynchronously

I have a method askGoogle that simulates sending http requests. I call askGoogle in a for loop 10 times. Each askGoogle call takes a random amount of time to get executed.

The 10 requests are sent asynchronously which means the 2nd request does not wait until the 1st is done before being sent, etc. Therefore sometimes it takes the very first request a longer amount of time to get finished which leads to the 4th or 8th requests to get executed earlier.

I want a message Done! to be printed after all requests have been finished.

I tried to accomplish this, but all my attempts have fallen short.

const https = require("https");

function askGoogle(i)  {
    setTimeout(() => {

        const googleRequest = https.request("https://google.com", {
            method: "GET"
        });
        googleRequest.once("error", err => {
            console.log("Something happened!");
        })
        googleRequest.once("response", (stream) => {
            stream.on("data", x => {
            });
            stream.on("end", () => {
                console.log("Done with google " + i);
                i++;
            })
        })
        googleRequest.end();
    }, getRandomInt(0, 5_000));
}

function findSolution() {
    for (let j = 0; j < 10; j++) {
        askGoogle(j);
    }
}

function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    let randomNumber = Math.floor(Math.random() * (max - min + 1)) + min;
    return randomNumber;
}

findSolution();
console.log("Done!");

output:

Done!
Done with google 7
Done with google 0
Done with google 4
Done with google 1
Done with google 8
Done with google 9
Done with google 6
Done with google 2
Done with google 3
Done with google 5

What I also tried:

(async () => {
    await findSolution();
    console.log("Done!");
})();

With the same result (Done! gets printed as the very first line).

Another attempt:

function findSolution(callback) {
    for (let j = 0; j < 10; j++) {
        askGoogle(j);
    }

    callback();
}

findSolution(() => {
    console.log("Done!");
})

With the same result (Done! gets printed as the very first line).

Why doesn't my code work as expected (The Done! message being the very last line in the output) and how do I fix it?

Upvotes: 0

Views: 538

Answers (1)

Hermosilla
Hermosilla

Reputation: 31

You can do this in multiple ways.

Perhaps the simplest is to return a promise in the 'askGoogle' function, and perform 'Promise.all' in 'findSolution' (on the list of obtained promises)

function askGoogle(i)  {
   return new Promise( (resolve, reject) => {
    setTimeout(() => {

        const googleRequest = https.request("https://google.com", {
            method: "GET"
        });
        googleRequest.once("error", err => {
            console.log("Something happened!");
            reject(err);
        })
        googleRequest.once("response", (stream) => {
            stream.on("data", x => {
            });
            stream.on("end", () => {
                resolve(i);
                console.log("Done with google " + i);
                i++;
            })
        })
        googleRequest.end();
    }, getRandomInt(0, 5_000));
   });
}
function findSolution() {
    const promises = [];
    for (let j = 0; j < 10; j++) {
        promises.push(askGoogle(j));
    }
    return Promise.all(promises);
}

Now, you can do:

findSolution().then(() => {
    console.log("Done!");
});  

or

await findSolution();  

console.log("Done!");

Upvotes: 2

Related Questions