Most of the server-side languages, like PHP, ASP.NET, Ruby, JAVA servers, follow multi-threaded architecture. That means, every request by the client results in the instantiation of a new thread or even a process.

However, in Node.js, all request are handled in a single thread with shared resources. Then how does Node.js handle concurrent traffic or requests? It follows “Single Threaded Event Loop Model” architecture that runs on top of single V8 engine instance.

Node.js is event-driven that implements background workers to achieve non-blocking asynchronous behavior. We called it the Observer Pattern. Node thread keeps an event loop and whenever a task gets completed, it fires the corresponding event which signals the event-listener function to execute as illustrated below.

As soon as Node.js starts, it initializes the event loop, processes the provided input script (i.e. initiates variables and declares functions) which may make async API calls, schedule timers, or call process.nextTick() , then begins processing the event loop.

Phases of the event loop

As shown in the figure aside, each phases has a FIFO queue of callbacks to be executed.

Overview of the Phases:

timers: this phase executes callbacks scheduled by setTimeout() and setInterval() .

pending callbacks: executes I/O callbacks deferred to the next loop iteration.

idle, prepare: only used internally.

poll: retrieve new I/O events; execute I/O related callbacks (almost all with the exception of close callbacks, the ones scheduled by timers, and setImmediate() ); NodeJs will block here when appropriate.

check: setImmediate() callbacks are invoked here.

close callbacks: some close callbacks, e.g. socket.on('close', ...) .

More detail on this can be read from the official docs.

Block diagram of NodeJs single-threaded event loop handling concurrent traffic.

As shown in the above block diagram, Node.js listens and passes every concurrent traffic in a queue, which will be executed by an event loop as explained above. Let’s see an example to observe this single-threaded architecture of a Node.js web application.

In the above example, we are using express-js which we need to install from npm. To run the above script, simply type the following command in your terminal.

$ node server.js // here, server.js is name of the file

Now, if we browse localhost:8002 in the browser, on every request, the visitorCount gets updated. Isn't that magic? In other programming languages, to achieve this, we will need to store that counter in some persistent storage. Here, as per the output, on every request, the visitorCount variable is being updated. That means, for all request, Node.js is running the same instance (thread/process) and visitorCount variable is same for all the request.

This is how Node.js works. Due to all these architectural implementations of Observer patterns, Node.js is pretty fast compared to similar other server-side languages and technologies.