behind the scene of node.js

behind the scene of node.js

Node.js is a JavaScript runtime environment that allows you to execute JavaScript code outside of the browser. It is commonly used to build scalable web servers, APIs, and real-time applications.

While Node.js provides an easy-to-use interface, understanding how it works under the hood can improve your Node development skills. In this article, we will take an in-depth look at the inner workings of Node.js.

Event-driven and non-blocking I/O

Node.js is built on the V8 JavaScript engine and libuv library. It employs an event-driven, non-blocking I/O model that makes it lightweight and efficient.

This means that instead of blocking while waiting for I/O, Node.js will register a callback function. When the I/O operation completes, that callback is called.

For example, when a request comes in, Node.js will not block the event loop while waiting for the response. Instead, it will register a callback and continue executing other tasks. Once the response is ready, the callback is called.

This event-driven model allows Node.js to handle thousands of simultaneous connections efficiently using a single-threaded event loop.

The Event Loop

Node.js has a single-threaded event loop that handles all events and callbacks. This event loop consists of:

  • Timers: Execute setTimeout() and setInterval() callbacks.

  • Pending callbacks: Execute I/O callbacks like those for network requests.

  • Idle, prepare: Perform miscellaneous tasks like garbage collection.

  • Poll: Check for new I/O events and execute their callbacks.

The event loop runs in a continuous cycle, checking each phase for events and executing their callbacks. This powers the non-blocking I/O of Node.js.

The libuv Library

The libuv library provides cross-platform support for I/O and asynchronous API in Node. It handles all I/O operations like:

  • Networking: TCP, UDP, Unix sockets, etc.

  • Filesystem: Open, read, write files.

  • Child processes.

  • Threadpool for performance-sensitive tasks.

When a request comes in, libuv passes it to the event loop as an I/O event. Once Node.js finishes handling the request, libuv sends the response back to the client.

Handling Requests and Responses

Node.js uses several objects to handle requests and responses:

  • http.Server represents the server and emits request events.

  • http.ClientRequest represents an outgoing request to a remote server.

  • http.IncomingMessage represents the incoming request.

  • http.ServerResponse represents the response that will be sent back to the client.

When a request comes in:

  1. Libuv reads the request data and passes it to Node.

  2. Node.js emits a request event, and passes the IncomingMessage and ServerResponse objects to the listener function.

  3. You modify the response object, call end() to send data back.

  4. Libuv sends the response using the TCP socket.

Hope this in-depth look at the inner workings of Node.js - from its event-driven model to request handling - helped you understand how it works "under the hood"! Let me know if you have any other questions.