EventEmitter3 is a high-performance EventEmitter that provides a drop-in replacement for Node.js's built-in EventEmitter with significant performance improvements. It maintains API compatibility while offering contextual event emission and optimized code paths for high-frequency event handling.
npm install eventemitter3const EventEmitter = require('eventemitter3');ESM:
import EventEmitter from 'eventemitter3';
// or
import { EventEmitter } from 'eventemitter3';TypeScript:
import EventEmitter from 'eventemitter3';
// With custom event types
import EventEmitter from 'eventemitter3';
interface MyEvents {
'data': [string, number];
'error': [Error];
'close': [];
}
const emitter = new EventEmitter<MyEvents>();const EventEmitter = require('eventemitter3');
const emitter = new EventEmitter();
// Add event listeners
emitter.on('data', (message) => {
console.log('Received:', message);
});
// Add one-time listener
emitter.once('ready', () => {
console.log('System ready!');
});
// Emit events
emitter.emit('data', 'Hello World');
emitter.emit('ready');
// Remove listeners
emitter.removeListener('data');
emitter.removeAllListeners();fn.bind)error event throwing, no newListener/removeListener eventsremoveListener removes ALL matching listeners, not just the firstCreates a new EventEmitter instance.
/**
* Creates a new EventEmitter instance
*/
function EventEmitter();
// TypeScript generic version
class EventEmitter<EventTypes = string | symbol, Context = any> {
constructor();
}Add, remove, and query event listeners with optional context support.
/**
* Add a listener for a given event
* @param {string|symbol} event - The event name
* @param {Function} fn - The listener function
* @param {*} [context] - The context to invoke the listener with
* @returns {EventEmitter} this - For method chaining
*/
on(event, fn, context);
/**
* Add a one-time listener for a given event
* @param {string|symbol} event - The event name
* @param {Function} fn - The listener function
* @param {*} [context] - The context to invoke the listener with
* @returns {EventEmitter} this - For method chaining
*/
once(event, fn, context);
/**
* Remove the listeners of a given event
* Note: Removes ALL matching listeners, not just the first
* @param {string|symbol} event - The event name
* @param {Function} [fn] - Only remove listeners that match this function
* @param {*} [context] - Only remove listeners that have this context
* @param {boolean} [once] - Only remove one-time listeners
* @returns {EventEmitter} this - For method chaining
*/
removeListener(event, fn, context, once);
/**
* Remove all listeners, or those of the specified event
* @param {string|symbol} [event] - The event name (removes all events if omitted)
* @returns {EventEmitter} this - For method chaining
*/
removeAllListeners(event);
/**
* Alias for on()
*/
addListener(event, fn, context);
/**
* Alias for removeListener()
*/
off(event, fn, context, once);Usage Example:
const emitter = new EventEmitter();
const context = { userId: 123 };
function handleData(data) {
console.log(`User ${this.userId} received:`, data);
}
// Add listener with context
emitter.on('data', handleData, context);
// Emit event - listener called with context
emitter.emit('data', 'message'); // User 123 received: message
// Remove specific listener
emitter.removeListener('data', handleData, context);Emit events to all registered listeners with optimized argument handling.
/**
* Calls each of the listeners registered for a given event
* Optimized for up to 6 arguments for performance
* @param {string|symbol} event - The event name
* @param {...*} args - Arguments to pass to listeners
* @returns {boolean} true if the event had listeners, false otherwise
*/
emit(event, ...args);Usage Example:
const emitter = new EventEmitter();
emitter.on('message', (text, priority, timestamp) => {
console.log(`[${priority}] ${timestamp}: ${text}`);
});
// Emit with multiple arguments
const hasListeners = emitter.emit('message', 'Hello', 'high', Date.now());
console.log('Event had listeners:', hasListeners); // trueQuery information about registered listeners and events.
/**
* Return an array listing the events for which the emitter has registered listeners
* @returns {Array<string|symbol>} Array of event names
*/
eventNames();
/**
* Return the listeners registered for a given event
* @param {string|symbol} event - The event name
* @returns {Function[]} Array of listener functions
*/
listeners(event);
/**
* Return the number of listeners listening to a given event
* @param {string|symbol} event - The event name
* @returns {number} Number of listeners
*/
listenerCount(event);Usage Example:
const emitter = new EventEmitter();
emitter.on('data', () => {});
emitter.on('error', () => {});
emitter.once('ready', () => {});
console.log(emitter.eventNames()); // ['data', 'error', 'ready']
console.log(emitter.listenerCount('data')); // 1
console.log(emitter.listeners('data')); // [function]Access EventEmitter configuration and constructor reference.
/**
* Indicates if event names are prefixed for compatibility
* @type {string|boolean} Either '~' or false
*/
EventEmitter.prefixed;
/**
* Reference to EventEmitter constructor (module namespace object)
* @type {Function} EventEmitter constructor
*/
EventEmitter.EventEmitter;Usage Example:
console.log(EventEmitter.prefixed); // '~' or false
console.log(EventEmitter.EventEmitter === EventEmitter); // trueEventEmitter3 includes comprehensive TypeScript definitions with generic type support.
interface ValidEventTypes = string | symbol | object;
interface EventEmitter<EventTypes = string | symbol, Context = any> {
eventNames(): Array<EventNames<EventTypes>>;
listeners<T extends EventNames<EventTypes>>(
event: T
): Array<EventListener<EventTypes, T>>;
listenerCount(event: EventNames<EventTypes>): number;
emit<T extends EventNames<EventTypes>>(
event: T,
...args: EventArgs<EventTypes, T>
): boolean;
on<T extends EventNames<EventTypes>>(
event: T,
fn: EventListener<EventTypes, T>,
context?: Context
): this;
once<T extends EventNames<EventTypes>>(
event: T,
fn: EventListener<EventTypes, T>,
context?: Context
): this;
removeListener<T extends EventNames<EventTypes>>(
event: T,
fn?: EventListener<EventTypes, T>,
context?: Context,
once?: boolean
): this;
removeAllListeners(event?: EventNames<EventTypes>): this;
addListener<T extends EventNames<EventTypes>>(
event: T,
fn: EventListener<EventTypes, T>,
context?: Context
): this;
off<T extends EventNames<EventTypes>>(
event: T,
fn?: EventListener<EventTypes, T>,
context?: Context,
once?: boolean
): this;
}
// Type helpers
type EventNames<T extends ValidEventTypes> = T extends string | symbol ? T : keyof T;
type EventListener<T extends ValidEventTypes, K extends EventNames<T>> =
T extends string | symbol
? (...args: any[]) => void
: (...args: ArgumentMap<Exclude<T, string | symbol>>[Extract<K, keyof T>]) => void;
type EventArgs<T extends ValidEventTypes, K extends EventNames<T>> =
Parameters<EventListener<T, K>>;TypeScript Usage Examples:
// Define event interface
interface AppEvents {
'user-login': [userId: string, timestamp: number];
'user-logout': [userId: string];
'error': [error: Error];
'ready': [];
}
const emitter = new EventEmitter<AppEvents>();
// Type-safe event handling
emitter.on('user-login', (userId, timestamp) => {
// userId and timestamp are properly typed
console.log(`User ${userId} logged in at ${timestamp}`);
});
emitter.on('error', (error) => {
// error is typed as Error
console.error('Application error:', error.message);
});
// Type-safe emission
emitter.emit('user-login', 'user123', Date.now()); // ✓ Valid
emitter.emit('user-login', 'user123'); // ✗ TypeScript error - missing timestampEventEmitter3 does not throw errors when emitting error events with no listeners, unlike Node.js EventEmitter.
const emitter = new EventEmitter();
// This does NOT throw an error (unlike Node.js EventEmitter)
emitter.emit('error', new Error('Something went wrong')); // Returns false
// To handle errors properly, always add an error listener
emitter.on('error', (err) => {
console.error('Caught error:', err);
});
emitter.emit('error', new Error('Something went wrong')); // Returns true, handledEventEmitter3 is optimized for high-performance scenarios:
arguments objectfn.bind() overhead// Optimized usage patterns
const emitter = new EventEmitter();
// Fast path - uses optimized argument handling
emitter.emit('event', arg1, arg2, arg3, arg4, arg5); // ✓ Optimized
// Context without binding overhead
emitter.on('event', handler, context); // ✓ Better than handler.bind(context)
// Efficient listener management
emitter.once('init', () => {}); // ✓ Automatic cleanup after first emission