Emittery is a simple and modern async event emitter for Node.js and browsers. It provides asynchronous event emission by default to prevent blocking operations, making it ideal for production applications where scalability and responsiveness are crucial.
npm install emitteryimport Emittery from "emittery";For CommonJS:
const Emittery = require("emittery");import Emittery from "emittery";
const emitter = new Emittery();
// Subscribe to events
emitter.on('π¦', data => {
console.log(data);
});
// Emit events asynchronously
await emitter.emit('π¦', 'π');
// One-time subscription
const data = await emitter.once('message');
// Subscribe to any event
emitter.onAny((eventName, data) => {
console.log(`Event ${eventName}:`, data);
});Emittery is built around several key concepts:
for await support for event streamsCore subscription functionality for listening to events with various patterns including single events, multiple events, and wildcard subscriptions.
on<Name extends keyof AllEventData>(
eventName: Name | readonly Name[],
listener: (eventData: AllEventData[Name]) => void | Promise<void>,
options?: {signal?: AbortSignal}
): UnsubscribeFunction;
once<Name extends keyof AllEventData>(
eventName: Name | readonly Name[],
predicate?: (eventData: AllEventData[Name]) => boolean
): EmitteryOncePromise<AllEventData[Name]>;
onAny(
listener: (eventName: keyof EventData, eventData: EventData[keyof EventData]) => void | Promise<void>,
options?: {signal?: AbortSignal}
): UnsubscribeFunction;Asynchronous event emission with both concurrent and sequential execution patterns for triggering listeners.
emit<Name extends keyof EventData>(
eventName: Name,
eventData: EventData[Name]
): Promise<void>;
emit(eventName: EventName): Promise<void>;
emitSerial<Name extends keyof EventData>(
eventName: Name,
eventData: EventData[Name]
): Promise<void>;
emitSerial(eventName: EventName): Promise<void>;Modern async iterator patterns for consuming event streams with for await loops and manual iteration control.
events<Name extends keyof EventData>(
eventName: Name | readonly Name[]
): AsyncIterableIterator<EventData[Name]>;
anyEvent(): AsyncIterableIterator<[keyof EventData, EventData[keyof EventData]]>;Helper methods for managing listeners, binding methods, and getting emitter state information.
off<Name extends keyof AllEventData>(
eventName: Name | readonly Name[],
listener: (eventData: AllEventData[Name]) => void | Promise<void>
): void;
clearListeners<Name extends keyof EventData>(eventName?: Name | readonly Name[]): void;
listenerCount<Name extends keyof EventData>(eventName?: Name | readonly Name[]): number;
bindMethods(target: Record<string, unknown>, methodNames?: readonly string[]): void;Constructor for creating new Emittery instances with optional configuration.
constructor(options?: Options<EventData>);
// Instance properties
debug: DebugOptions<EventData>;Development and debugging capabilities with configurable logging and meta-event tracking for monitoring emitter behavior.
static isDebugEnabled: boolean;
static readonly listenerAdded: unique symbol;
static readonly listenerRemoved: unique symbol;
static mixin(
emitteryPropertyName: string | symbol,
methodNames?: readonly string[]
): <T extends {new (...args: any[]): any}>(klass: T) => T;type EventName = PropertyKey;
// Core event data types
type AllEventData<EventData> = EventData & {
[listenerAdded]: ListenerChangedData;
[listenerRemoved]: ListenerChangedData;
};
interface Options<EventData> {
readonly debug?: DebugOptions<EventData>;
}
interface DebugOptions<EventData> {
readonly name: string;
readonly enabled?: boolean;
readonly logger?: DebugLogger<EventData, keyof EventData>;
}
type DebugLogger<EventData, Name extends keyof EventData> = (
type: string,
debugName: string,
eventName?: Name,
eventData?: EventData[Name]
) => void;
type UnsubscribeFunction = () => void;
interface ListenerChangedData {
listener: (eventData?: unknown) => void | Promise<void>;
eventName?: EventName;
}
type EmitteryOncePromise<T> = Promise<T> & {off(): void};