emit() is a synchronous for loop over an array of listeners. It calls each in registration order on the current stack and returns true if the event had at least one listener. Nothing is queued, so a listener that blocks blocks the emitter, and one that throws propagates out of emit() itself.
import { EventEmitter } from 'node:events';
class JobQueue extends EventEmitter {
add(name) { return this.emit('job', name); } // synchronous: every listener runs now
}
const q = new JobQueue({ captureRejections: true });
q.on('job', (name) => console.log('audit ', name));
q.once('job', (name) => console.log('first ', name)); // removed after one delivery
q.on('job', async () => { throw new Error('upload service down'); });
q.on('error', (err) => console.log('error ', err.message));
console.log('delivered', q.add('resize'), '| listeners', q.listenerCount('job'));
console.log('delivered', q.add('thumbnail'), '| listeners', q.listenerCount('job'));audit resize first resize delivered true | listeners 2 audit thumbnail delivered true | listeners 2 error upload service down error upload service down
The once listener is gone after the first delivery, so the count drops to two. The error lines arrive last: captureRejections routes a listener's rejected promise to the error event, and a rejection settles only on a later microtask. Without it you get an unhandled rejection, which by default kills the process (Unhandled Rejections).
error is treated specially: emitting it with no listener throws the argument instead of returning false, which is why a stream error crashes a program that listened only for data. Past ten listeners on one event Node prints a MaxListenersExceededWarning — a warning, not a limit, and usually a sign that a handler is added per request and never removed.
| Feature | EventEmitter | EventTarget |
|---|---|---|
| Used by | Node core APIs | Web APIs, AbortSignal |
| Payload | Any number of arguments | One Event object |
| Removal helper | once, off | { once: true }, signal |
| Error channel | 'error', throws if unhandled | No special event |