Executing concurrent HTTP requests

What is concurrency anyway? You’ve probably known or heard this term somewhere, so before going into specific implementation details, let me explain or refresh you about the concurrent part using Wikipedia:

In computer science, concurrency is the ability of different parts or units of a program, algorithm, or problem to be executed out-of-order or in the partial order, without affecting the outcome. This allows for parallel execution of the concurrent units, which can significantly improve the overall speed of the execution in multi-processor and multi-core systems.

With this in mind, let’s go straight to a use case where we need to write an application that executes multiple HTTP GET requests to an endpoint, stores each result in an array, and then logs the result into the terminal.

Helper function

In the script below, I implement a small helper function that uses axios to execute HTTP requests, at the same time these functions also logs in the terminal the time spent executing the HTTP request.

Non-concurrent requests

In the script below, where I manage to implement a function that takes n as a parameter, representing the number of requests to be executed.

The get function returns a promise object, so I am using the await keyword inside on an async. On this same function, I am also logging the overall execution time using the hrtime() method from the process package.

Due to the get function being called straight with the await keyword, the for statement only iterates next when the promise is resolved. In the image, bellow can see that each request is executed one after another.

Non concurrent

Concurrent requests

Since none of the results depend on each other, we can simply execute all the requests at once.

With just a few changes in the script above, it was possible to achieve a good level of concurrency and reduce the overall request’s execution time from 10s to 3s.

In the script below, I wrap all the unfulfilled request promises in an array and then I use Promise.all all of the 50 promises.

In the result bellow you can that the script took 3s seconds to execute 50 requests instead of 10 seconds as in the first script.

Concurrent requests

The Promise.all(results) method, returns a single promise when all the promises stored on results are fulfilled.

References

Firmino Changani

I'm Firmino, and here I write about web application development, focusing in Frontend, Backend and tooling tips that I learned and use.