Simple and modern async event emitter
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Asynchronous event emission with both concurrent and sequential execution patterns for triggering listeners.
Trigger events asynchronously with all listeners executing concurrently for maximum performance.
/**
* Trigger an event asynchronously with concurrent listener execution
* @param eventName - The name of the event to emit
* @param eventData - Optional data to pass to event listeners
* @returns Promise that resolves when all listeners complete or rejects if any listener throws
*/
emit<Name extends keyof EventData>(
eventName: Name,
eventData: EventData[Name]
): Promise<void>;
/**
* Trigger an event asynchronously without data
* @param eventName - The name of the event to emit
* @returns Promise that resolves when all listeners complete
*/
emit(eventName: EventName): Promise<void>;Usage Examples:
import Emittery from "emittery";
const emitter = new Emittery();
// Emit with data
await emitter.emit('user-created', {
id: '123',
name: 'Alice',
email: 'alice@example.com'
});
// Emit without data
await emitter.emit('ready');
// All listeners run concurrently
emitter.on('process-data', async (data) => {
// This listener might complete first
await fastOperation(data);
});
emitter.on('process-data', async (data) => {
// This listener runs in parallel
await slowOperation(data);
});
// Both listeners start immediately when emitted
await emitter.emit('process-data', someData);
console.log('All listeners completed');Trigger events asynchronously with listeners executing one after another in sequence.
/**
* Trigger an event asynchronously with sequential listener execution
* @param eventName - The name of the event to emit
* @param eventData - Optional data to pass to event listeners
* @returns Promise that resolves when all listeners complete sequentially, or rejects on first failure
*/
emitSerial<Name extends keyof EventData>(
eventName: Name,
eventData: EventData[Name]
): Promise<void>;
/**
* Trigger an event asynchronously without data, with sequential listener execution
* @param eventName - The name of the event to emit
* @returns Promise that resolves when all listeners complete
*/
emitSerial(eventName: EventName): Promise<void>;Usage Examples:
import Emittery from "emittery";
const emitter = new Emittery();
// Sequential processing where order matters
emitter.on('pipeline', async (data) => {
console.log('Step 1: Validating');
await validateData(data);
});
emitter.on('pipeline', async (data) => {
console.log('Step 2: Processing');
await processData(data);
});
emitter.on('pipeline', async (data) => {
console.log('Step 3: Saving');
await saveData(data);
});
// Listeners execute in the order they were registered
await emitter.emitSerial('pipeline', inputData);
console.log('Pipeline completed');
// If any step fails, remaining steps won't execute
try {
await emitter.emitSerial('critical-process', data);
} catch (error) {
console.error('Process failed at step:', error);
}Both emission methods handle errors differently:
Concurrent Emission (emit):
Sequential Emission (emitSerial):
import Emittery from "emittery";
const emitter = new Emittery();
// Concurrent error handling
emitter.on('data', async () => {
throw new Error('Listener 1 failed');
});
emitter.on('data', async () => {
console.log('Listener 2 still runs');
});
try {
await emitter.emit('data');
} catch (error) {
console.error('One listener failed:', error.message);
// Listener 2 still executed
}
// Sequential error handling
emitter.on('sequence', async () => {
throw new Error('Step 1 failed');
});
emitter.on('sequence', async () => {
console.log('This will not run');
});
try {
await emitter.emitSerial('sequence');
} catch (error) {
console.error('Sequence stopped:', error.message);
// Second listener never executed
}Emittery accepts various event name types for flexibility:
type EventName = PropertyKey; // string | symbol | numberUsage Examples:
import Emittery from "emittery";
const emitter = new Emittery();
// String event names (most common)
await emitter.emit('user-login', userData);
// Symbol event names (collision-resistant)
const INTERNAL_EVENT = Symbol('internal');
await emitter.emit(INTERNAL_EVENT, internalData);
// Number event names
await emitter.emit(404, errorData);emit() for independent listeners: When listeners don't depend on each other's completionemitSerial() for dependent operations: When listeners must complete in orderimport Emittery from "emittery";
const emitter = new Emittery();
// Good: Independent operations use concurrent emission
await emitter.emit('log-activity', activityData);
await emitter.emit('update-metrics', metricsData);
// Good: Dependent operations use sequential emission
await emitter.emitSerial('validation-chain', inputData);
// Good: Error handling
try {
await emitter.emit('risky-operation', data);
} catch (error) {
console.error('Operation failed:', error);
await emitter.emit('operation-failed', {error, data});
}Install with Tessl CLI
npx tessl i tessl/npm-emittery