EventEmitter API Reference¶
EventEmitter is the backbone of Node's asynchronous architecture Streams , HTTP servers , child processes , and half the Node API inherit from EventEmitter Know this API cold - it shows up everywhere
Module¶
const EventEmitter = require('events')
const EventEmitter = require('events').EventEmitter // same thing
Creating an EventEmitter¶
class MyEmitter extends EventEmitter {}
const emitter = new MyEmitter()
// Or create directly
const emitter = new EventEmitter()
Most Node objects that emit events are EventEmitter subclasses Stream , Server , Socket , Process , Readline , etc.
Methods¶
emitter.on(eventName, listener)¶
Adds a listener for the named event
emitter.on('data', (chunk) => {
console.log('Received:', chunk.length, 'bytes')
})
emitter.on('error', (err) => {
console.error('Error:', err.message)
})
emitter.addListener(eventName, listener)¶
Alias for emitter.on()
emitter.addListener('connect', () => console.log('connected'))
emitter.once(eventName, listener)¶
Adds a one-time listener - fires once then auto-removed
emitter.once('close', () => {
console.log('This runs only once')
})
// Example: first connection
server.once('connection', () => {
console.log('First client connected')
})
emitter.emit(eventName[, ...args])¶
Emits the named event , passing args to listeners Returns true if event had listeners , false otherwise
emitter.emit('data', Buffer.from('hello'))
emitter.emit('error', new Error('something broke'))
emitter.emit('status', 200, 'OK')
emitter.eventNames()¶
Returns array of event names with registered listeners
emitter.on('data', () => {})
emitter.on('end', () => {})
emitter.once('error', () => {})
console.log(emitter.eventNames())
// [ 'data', 'end', 'error' ]
Returns strings for named events , symbols for symbol-keyed events
emitter.getMaxListeners()¶
Returns the current max listener count (default 10)
console.log(emitter.getMaxListeners()) // 10
emitter.listenerCount(eventName)¶
Returns count of listeners for a specific event
emitter.on('data', handler1)
emitter.on('data', handler2)
console.log(emitter.listenerCount('data')) // 2
emitter.listeners(eventName)¶
Returns a copy of the array of listeners for the named event
emitter.on('data', myHandler)
const listeners = emitter.listeners('data')
console.log(listeners.length) // 1
console.log(listeners[0] === myHandler) // true
emitter.rawListeners(eventName)¶
Returns a copy of the array of listeners (including wrappers) Unlike listeners() , this returns the raw wrapped functions for once listeners
emitter.once('data', () => console.log('once'))
const raw = emitter.rawListeners('data')
console.log(raw[0].listener) // the original function
Useful for inspecting wrapped listeners - rarely needed
emitter.prependListener(eventName, listener)¶
Adds listener to the BEGINNING of the listeners array
emitter.on('data', () => console.log('second'))
emitter.prependListener('data', () => console.log('first'))
emitter.emit('data')
// first
// second
emitter.prependOnceListener(eventName, listener)¶
Adds one-time listener to the BEGINNING of the listeners array
emitter.prependOnceListener('close', () => console.log('runs first once'))
emitter.removeAllListeners([eventName])¶
Removes all listeners , or all listeners for a specific event
emitter.removeAllListeners() // removes everything
emitter.removeAllListeners('data') // removes only 'data' listeners
Be careful - this removes ALL listeners including system ones Prefer removeListener for surgical removal
emitter.removeListener(eventName, listener)¶
Removes a specific listener (must pass the same function reference)
function onData(chunk) {
console.log(chunk)
}
emitter.on('data', onData)
// Later...
emitter.removeListener('data', onData)
Anonymous functions can't be removed - keep references if you need to remove later
emitter.setMaxListeners(n)¶
Changes the max listener warning threshold Set to 0 for unlimited (but think twice)
emitter.setMaxListeners(20) // warn after 20 listeners
emitter.setMaxListeners(0) // unlimited (no warning)
The default warning at 10 listeners catches memory leaks If you intentionally need many listeners , set this higher - don't suppress the warning blindly
EventEmitter.defaultMaxListeners¶
Static property - changes default for ALL EventEmitter instances
EventEmitter.defaultMaxListeners = 50
// Affects ALL emitters created after this line
Use with extreme caution - setMaxListeners per-instance is cleaner
Error Events¶
emitter.on('error', (err) => {
console.error('Caught:', err.message)
})
emitter.emit('error', new Error('something broke'))
// Caught: something broke
If an 'error' event is emitted and there's no listener for it , Node throws the error and crashes the process
// CRASHES the process - no error listener
emitter.emit('error', new Error('unhandled'))
Always add an 'error' listener when you create or consume an EventEmitter This is the most common source of "unhandled error" crashes in Node apps
Async Event Patterns¶
Using async listeners¶
// Async listeners are supported but catch their errors
emitter.on('data', async (chunk) => {
// If this throws, the promise rejection is unhandled
await processChunk(chunk)
})
// Better: catch async errors explicitly
emitter.on('data', async (chunk) => {
try {
await processChunk(chunk)
} catch (err) {
emitter.emit('error', err)
}
})
Emitting async results¶
class AsyncEmitter extends EventEmitter {
async process(data) {
try {
const result = await someAsyncOperation(data)
this.emit('complete', result)
} catch (err) {
this.emit('error', err)
}
}
}
EventEmitter with AbortSignal¶
const ac = new AbortController()
emitter.on('data', (chunk) => {
if (ac.signal.aborted) return
console.log(chunk)
})
ac.signal.addEventListener('abort', () => {
emitter.removeAllListeners()
})
// Cancel all listeners
ac.abort()
Memory Leak Detection¶
// Node warns if you add more than 10 listeners to one event
for (let i = 0; i < 15; i++) {
emitter.on('data', () => {})
}
// (node) MaxListenersExceededWarning: Possible EventEmitter memory leak detected.
// 15 data listeners added to [MyEmitter]. Use emitter.setMaxListeners() to increase limit
The warning means you probably forgot to remove listeners - not that 11 listeners is bad
// Common leak pattern
function processData(stream) {
stream.on('data', (chunk) => {
// ...
})
// Listener is never removed
// Each call adds another listener
}
Prerequisites¶
- adv_06_streams_advanced.md - streams are built on EventEmitter