Event-driven architecture: navigating the single threaded nature of Node.js
Tags: node, eventdriven, javascript
Published: 2024-02-23 21:35:14



      

**JavaScript's 'comeback story'**
Despite its popularity nowadays, JavaScript had been once relegated to a simple scripting language primarily for client-side web development. 
Over the years, JavaScript has however experienced a resurgence, becoming a versatile and powerful language suitable for use across both the front and back-end in software development. 
One major factor to this resurgence is the development of **Node.js** which allowed for the execution of JavaScript on the server-side, thus giving rise to the _full-stack JavaScript developer_. 

---
**Lightweight and Efficient**

**Node.js** is a **lightweight runtime environment** which is built on the JavaScript V8 engine which allows for the rendering of JavaScript server-side. It is a lightweight, efficient, high performing environment which has allowed for the development of scalable and high-performance software such as

- real-time applications
- web servers
- web applications
- Command Line tools 

Node.js was written to provide JavaScript functionality on the back and since JavaScript is a **_single-threaded language_**, Node.js was developed using a single-threaded model.
This simply means that Node.js has a single event loop that executes only one task at a time, be it processing incoming requests, handling callbacks, and executing JavaScript code. 
Node.js however implements a **Non-blocking I/O (input/output)** model to bypass whatever bottlenecks that may arise in single-threaded execution. 
This allows for _input/output operations_ to be executed asynchronously allowing for the handling of a large number of concurrent connections which allows for the development of scalable applications.
The implementation of an **event-driven non-blocking I/O model** helps to eliminate a few performance issues one may experience using single-threaded systems. However one may still encounter some limitations which we discuss as well as some workarounds to them.

---
**Blocking Operations**:  Any synchronous or blocking operations can be encountered thus blocking an application's responsiveness and impacting performance 
In Node.js, synchronous methods may be found in either **native modules**; which are modules written outside as well as in the Node.js standard library. For example in the File System module, an attempt to read from the file system may be written as follows

```JavaScript
const fs = require('node:fs');
const data = fs.readFileSync('/file.md'); // blocks here until file is read. Synchronous methods end with the word Sync 
console.log(data);
moreWork(); // will run after console.log
```
Use of such synchronous methods may exhibit poor performance.
Node.js however provides alternative asynchronous methods to each synchronous blocking method.
Our previous example can thus be rewritten to provide **asynchronous**, non-blocking execution as follows;

```JavaScript
const fs = require('node:fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
});
```

Sometimes it is however not possible to use the non-blocking alternative of a synchronous method.
One vital tool Node.js provides for this scenario is **Libuv** which is an open-source library that is the core behind Node.js's event-driven, non-blocking model.

---
**Concurrency Limitations** - Node.js is built on a single loop, non-blocking event-driven system that allows it to manage I/O-intensive operations. 
 
![Event loop visual](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/10o0v2omhkx1iamnkg9h.png)


It is however a single-threaded system that uses **one event loop**. This causes serious issues when executing CPU-intensive tasks as applications are blocked from further execution. Node.js however provides an ingenious solution in **'worker threads'**.
 **Worker threads**, introduced in **v10.5** of Node.js provide for the offloading of CPU-intensive tasks out from the event loop allowing for the execution of threads in parallel in a non-blocking manner. They essentially provided a separate runtime for CPU-intensive tasks by offloading them from the main event loop and thus maintain application responsiveness. They are however used at a cost.

**Threading issues**
  Whilst a step forward towards achieving true parallelism using Node.js, the use of threads is not without a few challenges;
- Increased complexity; one must now manage the synchronization between the primary and worker threads.
- Restricted APIs; worker threads are only granted access to a restricted set of APIs not including DOM and UI APIs.
- Significant resource allocation; each thread is assigned its own instance of the V8 JavaScript engine.

Although solving the issue of limited concurrency, one must use worker threads conservatively and only when necessary.


---
**Error handling**
 The **asynchronous nature** of Node.js model which makes use of **<u>callback-based APIs</u>** may lead to **'callback hell'** as one may have to read through large amounts of code to identify the specific callback that is experiencing an error.
**<u>Uncaught exceptions</u>** might also terminate the Node.js process abruptly and can crash the application if not handled properly.
**<u>Stack traces</u>** which provide information on the sequence of function calls may not accurately provide a solution to finding the source of error as they are <u>asynchronous</u> in nature
Error handling and debugging in Node.js should be done using provided debugging tools and libraries.
Consistent error handling mechanisms such as use of the **'throw'** as well as the **'try...catch'** 
also provide for easier debugging.

Still the preferred solution
---
This article outlines a few factors one should consider when choosing to work with Node.js. Despite some limitations, workarounds have been provided by the brilliant contributors and developers that make Node.js a reality.
For scalable, efficient, high performing web-apps and real-time applications, Node.js is still a strong contender for the preferred environment to work with.