DEV Community

Manoj Kumar Patra
Manoj Kumar Patra

Posted on

The Node.js Platform

Node.js uses the concept of a module as the fundamental means for structuring the code of a program.

Node.js modules are created to be used, rather than extended. This has the advantage of reducing use cases, simplifying implementation, facilitating maintenance, and increasing usability.

# How Node.js works?

I/O (short for input/output) is definitely the slowest among the fundamental operations of a computer.

Node.js uses non-blocking I/O with the concept of event demultiplexing.

Multiplexing refers to the method by which multiple signals are combined into one so that they can be easily transmitted over a medium with limited capacity. Demultiplexing refers to the opposite operation, whereby the signal is split again into its original components.

Example code for event demultiplexing:


watchedList.add(socketA, FOR_READ)
watchedList.add(fileB, FOR_READ)
while (events = demultiplexer.watch(watchedList)) {
  // event loop
  for (event of events) {
    // This read will never block and will always return data data = event.resource.read()
    if (data === RESOURCE_CLOSED) {
      // the resource was closed, remove it from the watched list
      demultiplexer.unwatch(event.resource)
    } else {
      // some actual data was received, process it
      consumeData(data)
    }
  } 
}

Enter fullscreen mode Exit fullscreen mode


With this approach, the tasks are spread over time, instead of being spread across multiple threads.

Why not multiple threads??

Having a long-running thread for each connection and not using it for most of the time means wasting precious memory and CPU cycles.

Why not polling??

Polling algorithms usually result in a huge amount of wasted CPU time.

# The reactor pattern

Handles I/O by blocking until new events are available from a set of observed resources, and then reacts by dispatching each event to an associated handler.

The asynchronous behavior - The application expresses interest in accessing a resource at one point in time (without blocking) and provides a handler, which will then be invoked at another point in time when the operation completes.

# Libuv

Libuv is the I/O engine of Node.js.

Libuv makes Node.js compatible with all the major operating systems and normalizes the non-blocking behavior of the different types of resource.

Libuv also implements the reactor pattern, thus providing an API for creating event loops, managing the event queue, running asynchronous I/O operations, and queuing other types of task.

The full Node.js platform consists of the following:

  • A set of bindings responsible for wrapping and exposing libuv and other low-level functionalities to JavaScript.
  • V8, the JavaScript engine originally developed by Google for the Chrome browser which makes Node.js is so fast and efficient.
  • A core JavaScript library that implements the high-level Node.js API.

# JavaScript in Node.js vs the browser

  • Node.js doesn't have a DOM and nor a window or a document.
  • Node.js has access to a set of services offered by the underlying OS that are not available in the browser.
  • While the browser provides a higher-level abstraction over the operating system resources, which makes it easier to control and contain the code that runs in it, which will also inevitably limit its capabilities, with Node.js, on the other hand we can virtually have access to all the services exposed by the operating system.
  • Node.js officially provides support for implementing native modules via the N-API interface.

When developing a library meant to be used by third parties, we have to take into account that our code may run on different versions of Node.js. The general pattern in this case is to target the oldest active long-term support (LTS) release and specify the engines section in our package.json, so that the package manager will warn the user if they are trying to install a package that is not compatible with their version of Node.js.

Top comments (0)