EVENT LOOP
The Event Loop is the core mechanism that allows Node.js to handle non-blocking asynchronous operations on a single thread. It continuously processes different phases of events and executes callbacks when operations like I/O, timers, or promises are complete.
Features of EVENT LOOP-
1. Single-Threaded Execution– Operates on a single thread using non-blocking I/O. Prevents the need for thread management while handling multiple tasks.
2. Phased Operation Model– Processes tasks in well-defined stages: timers, I/O callbacks, poll, check, and close events. Each phase has specific responsibilities and processing rules.
3. Callback Handling– Executes registered callbacks once the corresponding event is triggered. Core to managing asynchronous code.
4. Microtask Queue Execution– Prioritizes internal operations like process.nextTick()
and Promises before re-entering the main loop. Ensures fine-grained control over scheduling.
5. libuv Integration– Delegates low-level I/O operations to libuv
, a C library. Enables true asynchronous behavior even though JavaScript is single-threaded.
6. Event-Driven Architecture– Powers Node’s reactive model, components emit events and respond through handlers. Used extensively via EventEmitter, HTTP servers, and sockets.
7. Automatic Task Scheduling– Continuously checks the event queue to determine which task is ready. Maintains efficient execution order based on event readiness.
8. Scalability Support– Allows high concurrency without blocking the main thread. Ideal for I/O-heavy tasks like file operations, API handling, and network services.
Importance of EVENT LOOP-
- Supports Single-Threaded Concurrency– Despite being single-threaded, Node.js handles multiple operations concurrently using the Event Loop, eliminating the need for multi-threaded management.
- Enables Asynchronous I/O– It allows Node.js to handle tasks like file access and network requests without blocking the main thread, promoting responsiveness.
- Improves Performance Under Load– By deferring expensive operations and processing callbacks only when ready, the Event Loop enhances scalability in real-world applications.
- Maintains Non-Blocking Execution– Code execution continues without waiting for I/O tasks to complete, ensuring smoother flow in web servers and CLI tools.
- Facilitates Event-Driven Architecture– It underpins Node’s design pattern where modules react to events (e.g., network responses), enabling modular and reactive programming.
- Efficient Resource Utilization– Offloads heavy I/O operations to background threads via libuv, allowing CPU cycles to be used for active tasks and callbacks.
- Manages Microtasks and Timers– Precisely controls execution order of Promises,
process.nextTick()
,setTimeout()
, andsetImmediate()
, affecting how asynchronous logic flows. - Foundation for Frameworks and Tools– The Event Loop powers libraries like Express, Socket.io, and build tools, making it a cornerstone of the Node.js ecosystem.
EXAMPLE-
console.log(‘Start’);
setTimeout(() => {
console.log(‘Timeout’);
}, 0);
Promise.resolve().then(() => {
console.log(‘Promise’);
});
process.nextTick(() => {
console.log(‘Next Tick’);
});
console.log(‘End’);
EVENTMITTER
EventEmitter
is a class in the built-in events
module of Node.js. It enables communication through events by allowing objects to emit named events and register listeners (callbacks) to respond when those events occur. This is central to Node’s event-driven architecture.
Features-
- Phased Architecture– Processes events in stages (timers, I/O, poll, check).
- Microtask Queue– Prioritizes Promises and
process.nextTick()
before main phases. - Non-Blocking Behavior– Prevents delays in execution, enhancing responsiveness.
- libuv Integration– Uses a C++ library to handle underlying system tasks asynchronously.
- Single-Threaded Execution– Manages asynchronous tasks without using multiple threads.
- Task Scheduling– Efficiently queues and processes callbacks as events complete.
- Event-Driven Design– Complements the architecture by triggering callbacks on readiness.
- High Scalability– Handles multiple operations concurrently, ideal for server applications.
Importance-
- Simplifies Asynchronous Workflows– Modules communicate using events rather than direct function calls or shared states.
- Facilitates Modular Design– Promotes separation of concerns by isolating event sources and listeners.
- Custom Event Creation– Developers can define application-specific events for better abstraction.
- Improves Maintainability– Changes to listeners or emitters are localized, making code easier to refactor.
- Supports Dynamic Runtime Behavior– Events can be added or removed based on runtime conditions.
- Used in Core Node APIs– Native objects like streams, HTTP servers, and child processes rely on EventEmitter.
- Ideal for Building Scalable Systems– Enables reactive patterns crucial for logs, user input, and distributed processing.
- Enables Event-Driven Programming– Allows components to react dynamically to events without tight coupling.
EXAMPLE-
const EventEmitter = require(‘events’);
const emitter = new EventEmitter();
emitter.on(‘message’, (data) => {
console.log(Received: ${data}
);
});
emitter.emit(‘message’, ‘Hello’);