Event Loop in Node.js


Objectives

Learn how event loop works in Node.js.

The basics

What is Node.js?

Node.js is a JavaScript runtime built on Chrome's V8 engine. It executes JavaScript code outside of a browser. It uses an event-driven, non-blocking I/O model that makes it lightweight and efficient.

JavaScript

JavaScript is a synchronous, blocking, single-threaded language.

The synchronous nature

In the code below, the first functionis logged then the second function is logged. This is because JavaScript is synchronous. It executes code line by line. What if the first function is a long-running function? The second function will have to wait until the first function is done. This is called blocking. The second function is blocked by the the first function 😔. This is not ideal because it makes the program slow and unresponsive.

Node.js Runtime

Here, Node.js comes to the rescue. Node.js is asynchronous and non-blocking. It uses a single thread to handle multiple requests. It provides us with several APIs that allow us to make asynchronous calls.

Let's take a look at the high-level architecture of Node.js. This is an image from this amazing article. I highly recommend you read it.

At its core, the Node runtime consists of three major components.

  • A JavaScript library that provides functions and utilities to tap into the C++ features from your JavaScript code
  • C++ features that provide for functionality such as file system access and networking
  • External dependencies — such as V8, libuv, crypto — required by Node.js for its functioning

While all the parts are important, the key component for asynchronous programming in Node.js is the external dependency, libuv.

What is libuv?

Libuv is a multi-platform C library that provides support for asynchronous I/O based on event loops. In the Node.js runtime, its role is to provide support for handling asynchronous operations. To dive deeper into libuv, this article is a great start. In short though, Libuv helps nodejs to perform these operations asynchronously and speed up the efficiency as well as performance whereas the main thread handles the operation and other workers complete the task. Libuv helps nodejs to enable smooth asynchronous operation.

What is event loop?

When Node.js starts, it initializes the event loop, processes the provided input script which may make async API calls, schedule timers, or call process.nextTick(), then begins processing the event loop.

The following diagram shows a simplified overview of the event loop's order of operations.

Each phase has a FIFO queue of callbacks to execute. When the queue has been exhausted or the callback limit is reached, the event loop will move to the next phase, and so on.

In action

Let's take a look at the code below. This is a typical asynchronous code.

Let's break it down step by step.

  1. The first console log statement is executed and "Hello from the first function" is logged on the console. This task is then completed and popped from the call stack.
  2. The setTimeout function is encountered, and its callback function is scheduled to run after a specified delay (in this case, 1000 ms). The setTimeout task is pushed to the queue, and the function continues to the next task.
  3. The third console log statement is executed, and "Hello from the third function" is logged on the console. This task is completed and popped from the call stack.
  4. Meanwhile, the event loop constantly checks if the call stack is empty. When the timer set by the setTimeout function runs out (i.e., after 1000 ms), the callback function for the setTimeout task is sent to the event queue.
  5. The event loop identifies that the call stack is empty and retrieves the next task from the event queue, which is the callback function for the setTimeout.
  6. The callback function is then pushed to the call stack and executed. "Hello from the second function" is logged on the console, and this task is subsequently popped from the call stack.

This is a very simple example of how the event loop works. In reality, the event loop is much more complex. For example, the event loop has multiple phases, and each phase has its own queue. Checkout the official documentation for more details.

Conclusion

In conclusion, the event loop is the backbone of Node.js. It is what makes asynchronous programming possible. Understanding how the event loop works is crucial to writing performant Node.js applications. I hope this article has helped you understand the event loop better. If you have any questions, feel free to leave a comment below. Thanks for reading!

Resources