Let’s do a deep dive into EventEmitter and event-driven design in Node.js. This is core to Node’s asynchronous architecture.
1️⃣ What is Event-Driven Design?
-
Event-driven programming = design pattern where code reacts to events rather than executing sequentially.
-
Instead of directly calling a function, you emit events and listen for them.
-
Enables decoupling, asynchronous handling, and non-blocking I/O.
Node.js itself is heavily event-driven (think: HTTP requests, streams, timers, I/O callbacks).
2️⃣ EventEmitter Basics
-
EventEmitter
is a core Node.js class (require('events')
) -
Allows registering listeners and emitting events
Import and Create Emitter
const EventEmitter = require("events");
const myEmitter = new EventEmitter();
Listening to an Event
myEmitter.on("greet", (name) => {
console.log(`Hello, ${name}!`);
});
-
.on(eventName, listener)
→ register listener for an event -
Multiple listeners can listen to the same event
Emitting an Event
myEmitter.emit("greet", "Tyson");
// Output: Hello, Tyson!
.emit(eventName, ...args)
triggers all listeners for that event
3️⃣ One-Time Event Listeners
.once
→ listener fires only once, then removed automatically
myEmitter.once("welcome", (user) => {
console.log(`Welcome, ${user}`);
});
myEmitter.emit("welcome", "Tyson"); // fires
myEmitter.emit("welcome", "Alice"); // ignored
4️⃣ Removing Listeners
const listener = (msg) => console.log(msg);
myEmitter.on("message", listener);
myEmitter.removeListener("message", listener);
- Prevents memory leaks in long-running apps
5️⃣ Practical Example: Event-Driven HTTP Server
const EventEmitter = require("events");
const http = require("http");
const serverEvents = new EventEmitter();
serverEvents.on("requestReceived", (url) => {
console.log(`Incoming request for ${url}`);
});
const server = http.createServer((req, res) => {
serverEvents.emit("requestReceived", req.url);
res.end("Hello, world!");
});
server.listen(3000, () => console.log("Server running on port 3000"));
-
The HTTP server emits custom events
-
You can handle logging, metrics, or analytics without cluttering the main request handler
6️⃣ EventEmitter with Streams
-
Node streams are built on EventEmitter
-
Examples:
-
readable.on("data", chunk => ...)
-
writable.on("finish", () => ...)
-
7️⃣ Key Takeaways
-
Node.js is event-driven at its core
-
EventEmitter
allows decoupling logic and asynchronous handling -
.on
= register listeners,.emit
= trigger events -
.once
= one-time listener -
Removing listeners prevents memory leaks
-
Event-driven design is widely used in HTTP servers, streams, WebSockets, and microservices
Next, we can go through child processes & clustering in Node.js, which is about scaling Node apps beyond a single thread.
Do you want to go there next?