Menu

Node.js EventEmitter: on, emit, once and Custom Events

EventEmitter from Node's events module lets an object announce named events with emit and lets other code react with on or once. Listeners run synchronously, in the order they were added.

This page includes runnable editors. Edit, run, and see output instantly.

EventEmitter is the class in Node's events module that lets an object announce named events. You register a listener with emitter.on('name', fn) and trigger it with emitter.emit('name', ...args); every listener for that name runs, in the order it was added, with the arguments you passed. HTTP servers, streams and process are all EventEmitters, so the same few methods work everywhere in Node.

Both listeners run between before emit and after emit: emit calls them synchronously and returns only when they are done. Swap the two shop.on calls and the two middle lines swap too.

on, once and off

on keeps a listener until you remove it, once removes it after the first call, and off (the same as removeListener) removes one. To remove a listener you need the same function you added, so name it instead of passing an arrow function inline.

first open ever prints once, after Ada. Once logOpen is removed nothing is listening, so the last emit returns false; door.removeAllListeners('open') would have cleared both listeners in one call.

MethodDoes
on(name, fn), addListenerCalls fn on every emit
once(name, fn)Calls fn on the next emit only
prependListener(name, fn)Like on, but runs before the existing listeners
off(name, fn), removeListenerRemoves that function
emit(name, ...args)Calls the listeners, returns true if there were any
listenerCount(name)How many listeners the event has

The error event

'error' is special. If you emit it and nobody listens, emit throws the error, and in a real program an uncaught throw crashes the process. Always add an 'error' listener to emitters that can fail, such as streams and servers.

Without a listener, emit throws and the catch gets it; with the listener added, the same emit just calls it and the program carries on. Any other event name with no listeners is silently ignored.

Extend EventEmitter in your own class

The usual way to use it is to make your class extend EventEmitter, call super() in the constructor and this.emit when something happens. Callers then subscribe to your object like to any Node object.

It prints 25%, 50%, 75%, 100% and then photo.png uploaded. Move up.start() above the two up.on lines and nothing prints: the events fire before anyone listens.

The same trap applies to emitting from a constructor. Libraries that must emit right away wrap the call in process.nextTick, which runs after the caller's on lines (see the event loop page).

Wait for an event with events.once

events.once(emitter, name) returns a promise that resolves with the event's arguments, as an array, the next time it is emitted. It turns a one-time event into something you can await, and it rejects if the emitter emits 'error' first.

The await pauses until the timer emits ready, then the array destructures into the two arguments. For an event that fires many times, events.on(emitter, name) gives an async iterator you can loop over with for await.

Common mistakes

Adding a listener inside a function that runs often. Calling on in every request handler stacks up listeners and memory. Add it once, or use once.

Removing an inline function. off('data', () => ...) removes nothing, because that arrow function is a new one. Keep a reference to the function you added.

Expecting listeners to run later. emit is synchronous, so a slow listener holds up the code that emitted. Marking the listener async does not help, because its code still runs on the same thread until the first await. Split heavy work into pieces with setImmediate between them, or move it to a worker thread.

Frequently Asked Questions

Is EventEmitter asynchronous?

No. emit calls every listener right away, one after another, and returns when the last one is done. Code inside a listener can start async work, but the listener itself is called synchronously.

What does the MaxListenersExceededWarning mean?

Node warns when more than 10 listeners are added for one event, because that often means a listener is added on every request and never removed. Remove the extra listeners, or call emitter.setMaxListeners(n) if you really need more.

What does emit return?

true if the event had at least one listener, false if nobody was listening. It does not return what the listeners return.

Which Node.js objects are EventEmitters?

Most of Node's core objects: HTTP servers, requests and responses, streams, sockets, process and readline interfaces. That is why they all share on, once and off.

Coddy programming languages illustration

Learn to code with Coddy

Get started