Node.js is not just another JavaScript runtime — it is a fundamentally different execution model from traditional multi-threaded servers like Apache or Java EE containers. When Dahl Ryan created Node.js in 2009, the driving motivation was the observation that most web server time is spent waiting: waiting for a database query to return, waiting for a file to be read from disk, waiting for a network response. In a multi-threaded server, each waiting operation blocks its thread, consuming memory and context-switch overhead for work that is mostly idle. Node.js solves this with a single-threaded event loop backed by a native library called libuv, which offloads I/O operations to the operating system and manages a pool of threads for the small subset of tasks that are genuinely CPU-blocking. Understanding this model is not academic — every performance decision, every scaling choice, and every architectural pattern in Node.js traces back to how the event loop works. Without this foundation, you will write code that accidentally blocks the loop, wonder why your server freezes under load, and misattribute the cause.
35 minintermediate
Event loop, libuv and threading model
Analogy🏏Cricket
🏏 Think of it like cricket: In a Test match, there are multiple types of scheduled breaks and interruptions, each with different priority levels and timing rules. The lunch break (setTimeout) is scheduled for a specific time but can be delayed if a wicket falls just before — it fires at the next available opportunity after its scheduled time, not at the exact scheduled time. The drinks break (setImmediate) is taken at the end of the current over, as soon as the ongoing delivery sequence finishes. The umpire's over-rate check (process.nextTick) happens immediately after each delivery, before the next batsman faces — it cannot be deferred. The DRS review resolution (Promise microtask) happens between deliveries, after the umpire check but before any scheduled breaks. Just as the match referee would be furious if an umpire kept conducting over-rate checks after every single ball indefinitely (starving nextTick), the event loop is unable to proceed if process.nextTick callbacks keep registering new nextTick callbacks recursively. The insight is that each timer primitive is not just a delay mechanism — it is a specific position in a formal protocol, and misusing it violates that protocol's invariants.
Lesson 1 of 36
0% complete