Skip to content

Node.js Events — Complete Guide to EventEmitter and Event-Driven Architecture

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Node.js Events. We cover key concepts, practical examples, and best practices to help you master this topic.

Node.js EventEmitter implements the Observer Patternver" >}} pattern, enabling objects to emit named events that trigger registered listener functions for asynchronous communication.

What You'll Learn

By the end of this tutorial, you'll use EventEmitter to create and handle custom events, manage listener lifecycles, extend EventEmitter in classes, and build event-driven architectures.

Why Events Matter

Node.js is fundamentally event-driven. HTTP servers, streams, and file operations all use events internally. Understanding EventEmitter helps you build decoupled, scalable systems.

Real-World Use

A chat server emits events when users connect, send messages, or disconnect. Different handlers Process each event independently, making the system modular and testable.

Events Learning Path

flowchart LR
  A[Buffers] --> B[Events]
  B --> C[Error Handling]
  C --> D[Debugging]
  D --> E[Express.js]
  A --> F{You Are Here}
  style F fill:#f90,color:#fff

Basic EventEmitter Usage

import { EventEmitter } from "node:events";
const emitter = new EventEmitter();
emitter.on("greet", (name) => {
  console.log(`Hello, ${name}!`);
});
emitter.emit("greet", "Alice");  // Hello, Alice!

Event Arguments

Events can pass multiple arguments to listeners.

emitter.on("data", (status, message, code) => {
  console.log(`[${status}] ${message} (${code})`);
});
emitter.emit("data", "OK", "Request successful", 200);
// Output: [OK] Request successful (200)

Once Listeners

Listeners registered with .once() fire at most one time.

emitter.once("connection", () => {
  console.log("First connection established");
});
emitter.emit("connection");  // Fires
emitter.emit("connection");  // Does nothing

Error Events

If an EventEmitter emits an 'error' event without a listener, Node.js throws the error and crashes the process.

emitter.on("error", (err) => {
  console.error("Caught error:", err.message);
});
emitter.emit("error", new Error("Something went wrong"));
// Caught error: Something went wrong

Managing Listeners

const listener = () => console.log("Event fired");
emitter.on("update", listener);

console.log(emitter.listenerCount("update"));  // 1
console.log(emitter.eventNames());              // ['update', ...]

emitter.removeListener("update", listener);
emitter.removeAllListeners("update");

Extending EventEmitter

class Logger extends EventEmitter {
  log(level, message) {
    const entry = `[${level}] ${message}`;
    this.emit("log", entry);
    if (level === "ERROR") {
      this.emit("error", new Error(message));
    }
  }
}
const logger = new Logger();
logger.on("log", (entry) => console.log(entry));
logger.on("error", (err) => console.error("Alert:", err.message));
logger.log("ERROR", "Connection refused");

Max Listeners Warning

By default, EventEmitter warns if more than 10 listeners are added to the same event. This prevents memory leaks.

emitter.setMaxListeners(20);  // Increase limit

Common Mistakes

1. Forgetting to Handle 'error' Events

An unhandled 'error' event crashes the process. Always attach an error listener to custom EventEmitters.

2. Adding Listeners Inside Loops

This creates multiple listeners unintentionally. Move listener registration outside loops.

3. Memory Leaks from Forgotten Listeners

Objects with listeners attached cannot be garbage collected. Remove listeners when no longer needed.

4. Using Arrow Functions When You Need to Remove Listeners

Arrow functions cannot be referenced for removal. Store the reference if you need to remove it later.

5. Emitting Events Before Listeners Are Registered

Events emitted before .on() calls are lost. Emit events only after listeners are attached.

Practice Questions

1. What is the difference between on and once?

on fires the listener every time the event is emitted. once fires the listener at most one time and then removes it.

2. What happens if an EventEmitter emits 'error' with no listener?

Node.js throws the error and crashes the process (if unhandled). Always register an error listener.

3. How do you remove a specific listener?

Call emitter.removeListener(event, listener) or emitter.off(event, listener) with a reference to the same function.

4. What is the default max listeners per event?

  1. Exceeding this logs a warning. Use setMaxListeners() to increase.

5. Challenge: Create a task queue that emits events when tasks are added, processed, and completed.

class TaskQueue extends EventEmitter {
  constructor() { super(); this.tasks = []; }
  add(task) {
    this.tasks.push(task);
    this.emit("added", task);
  }
  process() {
    while (this.tasks.length) {
      const task = this.tasks.shift();
      this.emit("processing", task);
      this.emit("completed", task);
    }
  }
}
const queue = new TaskQueue();
queue.on("completed", (task) => console.log(`Done: ${task}`));
queue.add("Send email");
queue.add("Generate report");
queue.process();

FAQ

Is EventEmitter synchronous or asynchronous?

EventEmitter calls listeners synchronously. Use process.nextTick or setImmediate for async behavior.

Can I emit events from a class without extending EventEmitter?

Compose with an EventEmitter instance instead of extending: this.emitter = new EventEmitter().

How many events can a single EventEmitter handle?

Limited only by memory. Each listener is a function reference stored in an internal map.

What is the difference between EventEmitter and callbacks?

Callbacks handle one completion. EventEmitter handles multiple events over time from a single source.

Does EventEmitter work in the browser?

Not natively, but the 'events' npm package provides a polyfill compatible with browsers.

Mini Project: Download Manager

Build a download manager that emits events for progress updates, completion, and errors.

import { EventEmitter } from "node:events";
import fs from "node:fs";
import https from "node:https";
class DownloadManager extends EventEmitter {
  download(url, dest) {
    this.emit("start", url);
    const file = fs.createWriteStream(dest);
    https.get(url, (response) => {
      const total = parseInt(response.headers["content-length"], 10);
      let downloaded = 0;
      response.on("data", (chunk) => {
        downloaded += chunk.length;
        this.emit("progress", { url, downloaded, total, percent: ((downloaded / total) * 100).toFixed(1) });
      });
      response.pipe(file);
      file.on("finish", () => this.emit("complete", url));
    }).on("error", (err) => this.emit("error", { url, error: err.message }));
  }
}
const dm = new DownloadManager();
dm.on("progress", (p) => process.stdout.write(`\r${p.url}: ${p.percent}%`));
dm.on("complete", (url) => console.log(`\nDownloaded: ${url}`));
dm.download("https://nodejs.org/dist/v22.0.0/node-v22.0.0-linux-x64.tar.gz", "node.tar.gz");

What's Next

Node.js Child Process Node.js Error Handling Express.js

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro