What is the EventEmitter pattern, and when should you use it?

3 minintermediatenodejseventemittereventspub-substreams

Quick Answer

EventEmitter is Node's built-in observer/pub-sub implementation: objects emit named events and listeners subscribe with `.on()`. It underpins streams, HTTP servers, and sockets. Use it for one-to-many, ongoing notifications (multiple events over time), where Promises (single future value) don't fit.

Detailed Answer

Answer: EventEmitter (from the events module) is the foundation of Node's event-driven APIs — HTTP servers, streams, sockets, and the process object are all emitters.

Basic usage:

const { EventEmitter } = require('events');

class Order extends EventEmitter {}
const order = new Order();

order.on('paid', (amount) => console.log(`Received $${amount}`));
order.once('shipped', () => console.log('Shipped!')); // fires at most once

order.emit('paid', 99);   // triggers the 'paid' listener
order.emit('shipped');

Key methods:

  • .on(event, fn) / .addListener — subscribe.
  • .once(event, fn) — subscribe for a single occurrence.
  • .emit(event, ...args) — fire synchronously, in listener registration order.
  • .off(event, fn) / .removeListener — unsubscribe (important to avoid leaks).

When to use EventEmitter vs Promises:

  • Promise/async-await: a single future result (a DB query, one HTTP request).
  • EventEmitter: a stream of events over time (data chunks, connection events, progress updates) — one-to-many, repeated.

Gotchas:

  • Listeners run synchronously; a throwing listener can crash unless handled.
  • An 'error' event with no listener throws and can crash the process — always handle 'error'.
  • Adding many listeners triggers a memory-leak warning at 10 by default (emitter.setMaxListeners(n) to adjust); usually the warning means you forgot to remove listeners.