Understanding Node.js Architecture: The Last Attempt

Understanding Node.js Architecture: The Last Attempt

To understand Node.js architecture, we first need to understand the Reactor Pattern which is the heart of Node.js

Reactor Pattern

The main idea behind it is to have a handler (which in Node.js is represented by a callback function) associated with each I/O operation, which will be invoked as soon as an event is produced and processed by the event loop. The structure of the reactor pattern is shown in the following image:

image.png

Everything starts with the application, the application makes requests and the event demultiplexer gathers those requests and then forms queues, Event Queues. Event demultiplexer is run by libuv, an asynchronous IO library that allows Node.js to perform I/O.

In the diagram, you see one event queue. actually, there is not only 1 event queue, there are 7 basic queues. those queues have ascending priorities, the queue with that highest priority is checked first by the event loop.

The Timers queue has the highest priority. setTimeout and setInterval functions get queued here. Once the events are done in this queue, or time is up, the event loop passes those functions to the call stack, in the diagram it is named execute handler.

Once one of the event queues is done, instead of jumping to the next queue, the event loop firstly will check 2 other queues which queue other micro tasks and process.nextTick functions. Then it will jump to the next queue. this diagram will help u visualize the event loop.

image.png

If there are no events in the event queue or the Event Demultiplexer has no pending requests, the program will complete.

note: callback queue that mentioned is event queue and the call stack is executed handler.

How libuv thread pool works?

When an event occurs it goes to the event queue and then gets picked up by the stack

the event does not get picked up by the stack. it is passed to the call stack by the event loop.

if it is a blocking request then the event loop passes it to a thread from a thread pool of libuv.

There are ONLY FOUR things that use the thread pool - DNS lookup, fs, crypto and zlib. Everything else executes in the main thread irrespective of blocking or not.

So logging is a network request and thread pool does not handle this. Neither libuv nor node has any code to handle these low-level operations that are involved with a network request. Instead libuv delegates the request making to the underlying operating system then it just waits on the operating system to emit a signal that some response has come back to the request. OS keeps track of connections in the network stack. But network i/o is handled by your network hardware and your ISP.

When is process.nextTick() in the NodeJS event loop called?

image.png process.nextTick() is not technically part of the event loop. Instead, the next tick queue will be processed after the current operation is completed, regardless of the current phase of the event loop. Next tick queue is displayed separately from the other four main queues because it is not natively provided by the libuv, but implemented in Node

Before each phase of the event loop (timers queue, IO events queue, immediate queue, close handlers queue are the four main phases), before moving to the phase, Node checks for the nextTick queue for any queued events. If the queue is not empty, Node will start processing the queue immediately until the queue is empty, before moving to the event loop next phase.

Sources: stackoverflow.com/questions/64264617/when-i.. stackoverflow.com/questions/56622353/how-do.. stackoverflow.com/questions/50718543/node-j..

Did you find this article valuable?

Support Sujeet Agrahari by becoming a sponsor. Any amount is appreciated!