Helper methods for managing listeners, binding methods, and getting emitter state information.
Remove previously registered event listeners from the emitter.
/**
* Remove one or more event subscriptions
* @param eventName - Single event name or array of event names
* @param listener - The exact listener function that was registered
*/
off<Name extends keyof AllEventData>(
eventName: Name | readonly Name[],
listener: (eventData: AllEventData[Name]) => void | Promise<void>
): void;Usage Examples:
import Emittery from "emittery";
const emitter = new Emittery();
// Save listener reference for later removal
const dataListener = (data) => {
console.log('Data received:', data);
};
// Register listener
emitter.on('data', dataListener);
// Remove specific listener
emitter.off('data', dataListener);
// Remove listener from multiple events
const multiListener = (data) => console.log(data);
emitter.on(['start', 'stop', 'pause'], multiListener);
emitter.off(['start', 'stop', 'pause'], multiListener);
// Anonymous functions cannot be removed
emitter.on('temp', () => console.log('temporary'));
// emitter.off('temp', ???); // No way to reference the anonymous functionRemove all listeners from the emitter or from specific events.
/**
* Clear all event listeners on the instance
* @param eventName - Optional specific event name(s) to clear. If omitted, clears ALL listeners including onAny listeners and async iterators
*/
clearListeners<Name extends keyof EventData>(eventName?: Name | readonly Name[]): void;Usage Examples:
import Emittery from "emittery";
const emitter = new Emittery();
// Add various listeners
emitter.on('data', handleData);
emitter.on('error', handleError);
emitter.onAny(logAllEvents);
// Clear listeners for specific event
emitter.clearListeners('data');
// Clear listeners for multiple specific events
emitter.clearListeners(['data', 'error']);
// Clear ALL listeners (including onAny)
emitter.clearListeners();
// This also clears any active async iterators
const iterator = emitter.events('stream');
emitter.clearListeners('stream'); // Iterator stops receiving eventsGet the number of active listeners for events.
/**
* Get the number of listeners for the specified events or all events
* Counts include: specific event listeners, onAny listeners, and active async iterators
* @param eventName - Optional specific event name(s) to count, or all events if omitted
* @returns Number of active listeners (includes all listener types and async iterators)
*/
listenerCount<Name extends keyof EventData>(eventName?: Name | readonly Name[]): number;Usage Examples:
import Emittery from "emittery";
const emitter = new Emittery();
emitter.on('data', handleData1);
emitter.on('data', handleData2);
emitter.on('error', handleError);
emitter.onAny(logAllEvents);
// Count listeners for specific event
console.log(emitter.listenerCount('data')); // 3 (2 specific + 1 any)
// Count listeners for multiple events
console.log(emitter.listenerCount(['data', 'error'])); // 4
// Count all listeners across all events
console.log(emitter.listenerCount()); // 4 total listeners
// Including async iterators in count
const iterator = emitter.events('stream');
console.log(emitter.listenerCount('stream')); // Includes iterator
await iterator.return(); // Clean upBind Emittery methods to other objects for convenient usage patterns.
/**
* Bind Emittery methods to a target object
* @param target - Object to bind methods to
* @param methodNames - Optional array of method names to bind, defaults to all methods
*/
bindMethods(target: Record<string, unknown>, methodNames?: readonly string[]): void;Usage Examples:
import Emittery from "emittery";
const emitter = new Emittery();
// Bind all methods to an object
const eventTarget = {};
emitter.bindMethods(eventTarget);
// Now you can use methods directly on the target
eventTarget.on('data', handleData);
eventTarget.emit('data', someData);
eventTarget.once('ready').then(() => console.log('Ready!'));
// Bind only specific methods
const logger = {};
emitter.bindMethods(logger, ['on', 'emit']);
logger.on('log', console.log);
logger.emit('log', 'This works!');
// logger.once('test'); // Error: once method not bound
// Useful for API objects
class MyAPI {
constructor() {
this.emitter = new Emittery();
this.emitter.bindMethods(this, ['on', 'off', 'once']);
}
// Now this class can be used directly as an event emitter
async performAction() {
// Internal emit
await this.emitter.emit('action-complete', {result: 'success'});
}
}
const api = new MyAPI();
api.on('action-complete', handleCompletion); // Works directlyimport Emittery from "emittery";
class EventManager {
constructor() {
this.emitter = new Emittery();
this.listeners = new Map();
}
// Managed listener registration
addListener(eventName, listener, id) {
this.emitter.on(eventName, listener);
this.listeners.set(id, {eventName, listener});
}
// Remove by ID
removeListener(id) {
const entry = this.listeners.get(id);
if (entry) {
this.emitter.off(entry.eventName, entry.listener);
this.listeners.delete(id);
}
}
// Get statistics
getStats() {
return {
totalListeners: this.emitter.listenerCount(),
managedListeners: this.listeners.size,
events: Array.from(this.listeners.values())
.map(entry => entry.eventName)
};
}
// Clean up all managed listeners
cleanup() {
for (const [id] of this.listeners) {
this.removeListener(id);
}
}
}import Emittery from "emittery";
const emitter = new Emittery();
// Clean up listeners based on conditions
function cleanupInactiveListeners() {
// This is a conceptual example - actual implementation
// would need to track listener metadata
// Clear listeners that haven't been triggered recently
if (shouldCleanup()) {
emitter.clearListeners('rarely-used-event');
}
// Or clear everything and re-register essential listeners
if (needsReset()) {
emitter.clearListeners();
registerEssentialListeners();
}
}
function registerEssentialListeners() {
emitter.on('error', handleCriticalError);
emitter.on('shutdown', handleShutdown);
}import Emittery from "emittery";
// Pattern 1: Service wrapper
class EventService {
constructor() {
this.emitter = new Emittery();
// Expose only specific methods
this.emitter.bindMethods(this, ['on', 'emit']);
}
// Add service-specific methods
broadcast(message) {
return this.emit('broadcast', message);
}
}
// Pattern 2: Mixin approach
function addEventCapabilities(target) {
const emitter = new Emittery();
emitter.bindMethods(target);
// Add cleanup capability
target.cleanup = () => emitter.clearListeners();
return target;
}
// Pattern 3: Selective binding
class APIClient {
constructor() {
this.emitter = new Emittery();
// Only bind listener methods, not emission
this.emitter.bindMethods(this, ['on', 'off', 'once']);
}
// Keep emission internal
async makeRequest() {
try {
const result = await fetch('/api/data');
await this.emitter.emit('success', result);
} catch (error) {
await this.emitter.emit('error', error);
}
}
}Proper cleanup is important to prevent memory leaks:
import Emittery from "emittery";
const emitter = new Emittery();
// Always clean up when done
function setupTemporaryListeners() {
const listeners = [];
// Track listeners for cleanup
listeners.push(emitter.on('temp1', handler1));
listeners.push(emitter.on('temp2', handler2));
// Clean up later
return () => {
listeners.forEach(unsubscribe => unsubscribe());
};
}
const cleanup = setupTemporaryListeners();
// ... later
cleanup();
// Or clear entire events
emitter.clearListeners(['temp1', 'temp2']);
// Monitor listener count in development
if (process.env.NODE_ENV === 'development') {
setInterval(() => {
const count = emitter.listenerCount();
if (count > 100) {
console.warn(`High listener count: ${count}`);
}
}, 10000);
}