The Reactor Pattern
Understand how readiness events and handlers enable non-blocking I/O.
Lesson content
🎯 Goal By the end of this lesson, you'll understand: What is the Reactor Pattern? Why Node.js uses it How it works Components of the Reactor Pattern Real-world examples Interview questions What is the Reactor Pattern? The Reactor Pattern is a software design pattern used to handle multiple I/O events efficiently using a single thread . Node.js follows the Reactor Pattern to manage thousands of client requests without creating a new thread for each request. Simple Definition: The Reactor Pattern waits for events and executes the appropriate callback when an event occurs. Why Do We Need the Reactor Pattern? Imagine 1,000 users visiting a website. Without the Reactor Pattern: ❌ One thread per request ❌ High memory usage ❌ Poor scalability With the Reactor Pattern: ✅ One Event Loop ✅ Many connections ✅ Efficient resource usage Real-Life Example ☎️ Imagine a receptionist answering phone calls. Customer 1 → Calls Customer 2 → Calls Customer 3 → Calls The receptionist doesn't stay on one call until it finishes. Instead: Answers a call Forwards it to the correct department Answers the next call Handles responses when departments finish The receptionist is like the Reactor . Components of the Reactor Pattern Client │ ▼ Event Demultiplexer (OS/libuv) │ ▼ Event Loop (Reactor) │ ▼ Callback Handler 1. Event Source Generates events. Examples: HTTP Request File Read Timer Database Response 2. Event Demultiplexer Managed by the Operating System and libuv . It waits for I/O events. 3. Event Loop (Reactor) Continuously checks for completed events. 4. Event Handler Executes the callback. How It Works Client Request │ ▼ Node.js Receives Request │ ▼ Registers Callback │ ▼ libuv Waits │ ▼ Task Completes │ ▼ Event Loop │ ▼ Execute Callback Example const fs = require ( "fs" ); console . log( "Start" ); fs . readFile( "test.txt" , () => { console . log( "File Read" ); }); console . log( "End" ); Output Start End File Read Step-by-Step Step 1 fs . readFile(...) Registers a callback. Step 2 libuv starts reading the file. Step 3 JavaScript continues executing. console . log( "End" ); Step 4 When the file is ready: Event Loop │ ▼ Callback Executes Visualization Client │ ▼ HTTP Request │ ▼ Node.js │ ▼ Event Loop │ ▼ libuv │ ▼ OS Waits │ ▼ Event Ready │ ▼ Callback Executes HTTP Server Example const http = require ( "http" ); const server = http . createServer(( req , res ) => { res . end( "Hello Node.js" ); }); server . listen( 3000 ); When multiple users send requests: User 1 ─┐ User 2 ─┼──► Event Loop User 3 ─┘ The Event Loop dispatches each request to its callback without creating a new JavaScript thread. Reactor Pattern vs Traditional Thread Model Traditional Server Reactor Pattern One thread per request One Event Loop handles many requests High memory usage Low memory usage Limited scalability Highly scalable Blocking I/O Non-blocking I/O Where is the Reactor Pattern Used? ✅ HTTP Servers ✅ Express.js Applications ✅ Chat Applications ✅ API Servers ✅ Streaming Services ✅ WebSocket Servers Why is Node.js Fast? Because it combines: Event Loop libuv Non-Blocking I/O Reactor Pattern This allows one process to handle many concurrent I/O operations efficiently. Interview Question Which design pattern does Node.js use for handling I/O? Answer: The Reactor Pattern , implemented using the Event Loop and libuv , to efficiently process asynchronous, non-blocking I/O events. Best Practices ✅ Use asynchronous APIs to take advantage of the Reactor Pattern. ✅ Keep callbacks and Event Loop tasks lightweight. ✅ Use Worker Threads for CPU-intensive tasks. ❌ Avoid blocking the Event Loop with long synchronous operations. Key Points ✅ Node.js follows the Reactor Pattern . ✅ The Event Loop is the core of the Reactor Pattern. ✅ libuv waits for I/O events and notifies the Event Loop. ✅ Callbacks execute only when their associated events are ready. ✅ The Reactor Pattern enables Node.js to handle many concurrent connections efficiently. 🧠 Easy Formula Client Request │ ▼ Register Callback │ ▼ libuv Waits │ ▼ Event Ready │ ▼ Event Loop │ ▼ Execute Callback Reactor Pattern = Event Loop + libuv + Non-Blocking I/O + Callbacks Remember: 🎯 Reactor Pattern = Wait for events, then execute callbacks. 🔄 Event Loop acts as the Reactor. ⚙️ libuv detects completed I/O operations. 🚀 Together, they allow Node.js to efficiently handle thousands of concurrent connections on a single JavaScript thread.