Skip to the solution
MediumLow-Level Design6 min read

What are EventEmitters in Node.js?

847 views

The problem

Question presented to candidate: "You register two listeners for the same custom event and emit it once. What order do they fire in, and what happens if you emit an 'error' event with no listener registered for it at all?"

What a strong answer should cover:

  • EventEmitter is Node's built-in publish/subscribe primitive: .on(event, listener) registers a callback, .emit(event, ...args) synchronously invokes every listener registered for that event, in registration order.
  • Multiple listeners on the same event all fire, in the order they were added β€” verified directly, not just documented, with two listeners producing a strictly ordered result.
  • .once(event, listener) registers a listener that fires at most one time, automatically removing itself after its first invocation β€” verified across two .emit() calls firing only once.
  • .emit() returns a boolean β€” true if the event had at least one listener, false if it had none β€” a real, checkable return value, not merely a side-effecting call.
  • πŸ“Œ The critical, special-cased behavior: emitting 'error' on an EventEmitter with no listener registered for it throws synchronously rather than silently doing nothing β€” this is a deliberate design choice specifically for the 'error' event name, different from every other event, and is why every stream/socket/emitter-based API in Node's ecosystem needs an 'error' listener attached.
  • EventEmitter is the foundation underneath Streams, net.Socket, http.Server, and much of Node's standard library β€” understanding it deepens understanding of all of those, not just custom application-level events.

Clarifying questions expected:

  • "Is the concern custom application events, or understanding a built-in class (a stream, a socket) that happens to extend EventEmitter?" β€” the mechanics are identical either way.
  • "Does the codebase register an 'error' listener on every emitter that might emit one?" β€” the special-cased throw-on-no-listener behavior makes this a real, checkable requirement, not just good practice.

Code / implementation expected: Yes β€” actually demonstrating listener order, .once(), the boolean return value, and the special 'error'-with-no-listener throw is the concrete, convincing version of this answer.

  • event emitter
  • events
  • architecture
  • design patterns

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

6 min read Β· 9 sections

Read the code

JavaScriptEventEmitter listener order, once(), the emit() boolean return, and the special 'error'-with-no-listener throw β€” all verified
const EventEmitter = require("events");
const emitter = new EventEmitter();

const order = [];
emitter.on("greet", () => order.push("listener1"));
emitter.on("greet", () => order.push("listener2"));
emitter.emit("greet");
console.log(order); // [ 'listener1', 'listener2' ] β€” registration order

let onceCount = 0;
emitter.once("single", () => onceCount++);
emitter.emit("single");
emitter.emit("single");
console.log(onceCount); // 1 β€” fired only once across two emits

console.log(emitter.emit("nothing-listens")); // false
console.log(emitter.emit("greet"));            // true

try {
  emitter.emit("error", new Error("boom"));
} catch (e) {
  console.log(e.message); // boom β€” thrown SYNCHRONOUSLY, unlike any other event
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 63 of 152 in Node.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Node.js questions
Up nextMedium

How do you design liveness and readiness health-check endpoints?

Continue