Everything you need to finally understand what's really behind Node.js

27.07.2022Ricky Elfner
Tech JavaScript Node.js

Most of you will definitely have heard of Node.js and will certainly know where it is used. But many of you don’t really know how it works and what functions it provides. That is why we will take a closer look at Node.js in this techup. 🤠

First of all, Node.js is not a programming language and not a framework. It is more of a runtime environment that is based on JavaScript and is used to be able to use various frameworks properly in the first place. Node.js was developed in 2009 by Ryan Dahl. Before its introduction, JavaScript was mainly used in the frontend to interact with a user and generate dynamic content. But this changed with Node.js, because now it was also possible to use server-side programming with JavaScript. This means that the JavaScript code is no longer only executed on the client side, but can also be executed on the back end. Node.js uses the runtime environment V8, which was developed for Google Chrome. Another important feature of Node.js is its event-based mode of operation, so it reacts to input from a user or to http calls.

Areas of application

In the meantime, Node.js can be found in the most diverse areas. Even big names like Twitter, Spotify or eBay rely on this runtime. Thereby, Node.js can be used within the most diverse applications. Examples of this are:

  • Data Streaming
  • IoT applications
  • Complex SPAs
  • REST API Server
  • Web Applications
  • Real Time Chats

Timeline

The following graph shows how Node.js has developed since the first version in 2009.

nodejs_03

Structure

nodejs_01

Libuv

As mentioned earlier, Node.js relies on asynchronous communication instead of thread-based events. This is also defined as non-blocking I/O, because here a separate new thread is not started for each request, but instead single threads are used. These are processed one after the other in an endless loop, which prevents blocking of the process. Libuv is used to process the threads. This is a “multi-platform support library “ written in C, which has specialised in asynchronous I/O. Libuv was deliberately developed for Node.js, but is now also used in Levit, Julia and other projects.

This has the advantage that when an I/O operation needs access to a database, for example, the thread is not blocked, but Node.js only finishes the actual task when the response comes back. Node.js can thus continue with other tasks in the meantime.

Structure of Libuv

The Libuv structure can actually be divided into two layers. The upper layer with Network I/O, File I/O, DNS. Operations and User Code, defines the interfaces that can be used by Libuv users. The lower layer is responsible for handling cyclic I/O queries, as well as the worker threads. IOCP is responsible for I/O polling of windows, while epoll, kqueue and event ports are responsible for systems.

image_01

Two other concepts to be aware of are handles and requests. Handles are abstractions of resources, such as TCP and UDP sockets. Once a job is done, the handle calls the associated callback. These are also called long-lived objects, because they take over this task as long as they are active. Requests, on the other hand, are short-lived operations. These operations are executed directly via a handle, and are comparable to functions or methods.

Finally, the thread pool should be mentioned, which can be seen at the top of the diagram. This is responsible for File I/O and the DNS search. However, the callbacks are executed in the main thread. Since it is possible since Node version 10.5 to also execute JavaScript in parallel via the worker threads, the default size of 4 can be increased by means of an environment variable.

Event Loop

One of the most important features of Node.js is the event loop, or sometimes called the event stack. This loop describes how it is possible for Node.js to work asynchronously, and achieve non-blocking I/O. The Node.js JavaScript code runs on a single thread, so exactly one thing happens at a time. This also means that you don’t have to worry about parallelism problems. However, you have to be careful when writing code that you don’t block a thread with network calls or infinite loops.

For example, each Chrome tab has its own event loop so that each process runs in isolation and does not block other tabs or even the whole browser. Thus, there are several different event loops. Up to this point, the servers always had to start a separate thread for each task. The event loop checks all the time whether there is a function within the call stack that needs to be executed. This stack works according to the LIFO principle (Last In, First out).

Job Queue

In 2015, the concept of the Job Queue was introduced by means of ECMA Script. Here Promises are used to take advantage of the fact that results of an async function are available as quickly as possible. This is because they are not added to the end of the call stack, but are called immediately after the current function has finished.

Node Core

The Node Core primarily includes the V8 Engine, which is a JIT compiler. This allows permanent switching between compiling and executing code. The big advantage created is that the engine can collect information that can be directly used in the next step when compiling. In addition to this and the Libuv dependency, there are libraries such as OpenSSL or HTTP parsers. These wrappers are necessary because the V8 Engine is very restrictive and does not allow access to the file system, for example.

The Package Manager

Another feature that Node.js offers is the Node Package Manager. This allows you to use additional modules. Although some useful modules are already delivered by default, the possibilities for extension are enormous. The packages can be installed via CLI (npm). For many basic things, there are already modules that provide desired functions that can save a lot of time. It is also possible to provide a certain standardisation.

Frontend or backend

Another question that is often asked is whether Node.js is used in the frontend or in the backend. Basically, it can be used for both, as there are now also Node.js frameworks such as Express.js. Express.js is also used within the widespread MERN stack (MongoDB, Express, React, Node). Another point here is the increased efficiency, as developers no longer have to switch between different programming languages.

Advantages

Since JavaScript is one of the languages that are relatively easy to learn, thanks to Node.js one has the advantage that JavaScript can now also be used for backend-side tasks. In addition, Node.js is strongly scalable and also fast in processing data. Thanks to asynchronous events, non-blocking I/O can be achieved, since you no longer have to wait until a task is completed. Instead, callbacks are used to continue with the task only when the necessary result is available. With NPM, you can use existing functions and concentrate on your actual programme. Since the community around Node.js is now very large, you can hope for good support in various forums.

Disadvantages

When writing your own code, you must bear in mind that everything must be built with callbacks. This also means that the code here will quickly become unmanageable and difficult to manage. Another point to consider is accessing databases, as these can usually only process a certain number of requests. Here you would still have to use a queue system. Since Node.js is single-threaded, this runtime is not well suited if you have many CPU-intensive tasks.

Node.js Frameworks and Tools

  • AdonisJS: This is a fully-featured TypeScript-based framework that focuses heavily on the developer, as well as stability and trust. Additionally, it is one of the fastest Node.js frameworks.
  • Gatsby: This is a static site generator, which is based on React and supports GraphQL. The big advantage here is the choice of plugins.
  • Next.js: Another framework which is based on React. Important functions such as Hybrid Static & Server Rendering, TypeScript Support, Smart Bundling, Route pre-fetching are provided out of the box.
  • Express: Express provides one of the simplest and most powerful ways to deploy a web server.

Conclusion

If you think about what you want to use your application for beforehand, and can rule out any computationally intensive tasks, it definitely makes sense to use Node.js. That’s why many frameworks rely directly on Node.js. Node.js can show its strength especially in REST services, streaming or single-page applications. You can also benefit from the large community all around.

However, one should also be aware of the disadvantages of Node.js. Namely, potentially confusing code due to a large number of callbacks, potential limitation of database access, and unsuitability for CPU-intensive tasks.

Soon we will definitely take a closer look at Deno and see what the differences are to Node.js. What makes it different and better or worse. Stay tuned! 💪

Ricky Elfner

Ricky Elfner – Denker, Überlebenskünstler, Gadget-Sammler. Dabei ist er immer auf der Suche nach neuen Innovationen, sowie Tech News, um immer über aktuelle Themen schreiben zu können.