NodeJSThe EventEmitter Class

The EventEmitter Class

EventEmitter is the concrete implementation of Node's event-driven model. It is a small, elegant class: an internal map from event names to arrays of listener functions, plus methods to add, remove, and fire them. Because so much of Node inherits from it — servers, streams, sockets, process — understanding the class itself pays off everywhere.

Creating one

JS
import { EventEmitter } from 'node:events'

const emitter = new EventEmitter()

emitter.on('greet', (name) => console.log(`Hello, ${name}`))
emitter.emit('greet', 'Ada')   // → Hello, Ada
Hello, Ada
What lives inside

Conceptually, an emitter is just a registry. Picturing the internal structure demystifies every method:

The emitter's internal state

Text
emitter._events = {
  'greet':  [ fn1 ],            // one listener
  'data':   [ fnA, fnB, fnC ],  // three, called in this order
  'error':  [ errHandler ],
}

emit('data', x)  →  fnA(x); fnB(x); fnC(x)   // synchronous, in array order
The full method set

Method

Effect

on(name, fn)

Append a listener (alias addListener)

once(name, fn)

Listener that removes itself after one call

prependListener(name, fn)

Add to the front of the queue

emit(name, ...args)

Call every listener for name with args

off(name, fn)

Remove a specific listener (alias removeListener)

removeAllListeners([name])

Clear listeners for one or all events

listeners(name)

Array of the current listener functions

listenerCount(name)

Number of listeners attached

setMaxListeners(n)

Raise/lower the leak-warning threshold

emit returns whether anyone listened

emit returns true if the event had listeners, false otherwise — useful for "fire only if someone cares" logic:

JS
const e = new EventEmitter()
console.log(e.emit('nobody'))        // false — no listeners
e.on('hi', () => {})
console.log(e.emit('hi'))            // true  — one listener ran
this inside a listener
A regular-function listener binds `this` to the emitter — arrows don't
If you register with a `function () {}`, `this` inside it is the emitter, which lets you call `this.removeListener`. If you register with an arrow `() => {}`, `this` keeps its surrounding lexical value (often your class instance) — usually what you actually want. Pick deliberately; mixing them up is a classic source of "`this` is undefined" bugs.

JS
emitter.on('ping', function () {
  console.log(this === emitter)   // true — regular function
})

emitter.on('ping', () => {
  console.log(this === emitter)   // false — arrow keeps outer this
})
Order, and jumping the queue

Listeners fire in the order added. prependListener and prependOnceListener insert at the front when you need a handler to run first:

JS
const e = new EventEmitter()
e.on('x', () => console.log('second'))
e.prependListener('x', () => console.log('first'))
e.emit('x')
first
second
Inherit it for your own types

The standard pattern is class X extends EventEmitter. Always call super() so the internal registry is initialized:

JS
import { EventEmitter } from 'node:events'

class Timer extends EventEmitter {
  start(ms) {
    this.emit('start')
    setTimeout(() => this.emit('done'), ms)
    return this   // chainable, like Node's own emitters
  }
}

new Timer()
  .on('start', () => console.log('go'))
  .on('done', () => console.log('finished'))
  .start(100)
Composition is a valid alternative
You don't *have* to inherit. For classes that already extend something else, hold an emitter as a field (`this.events = new EventEmitter()`) and expose `on`/`emit` wrappers. Inheritance reads more naturally for "this object *is* an event source"; composition fits "this object *has* events among other concerns".
Next
Put it into practice — the patterns for emitting and subscribing cleanly: [Emitting & Listening to Events](/nodejs/emitting-events).