CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-eventemitter3

High-performance EventEmitter with Node.js compatibility and contextual event emission

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

index.mddocs/

EventEmitter3

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.

Package Information

  • Package Name: eventemitter3
  • Package Type: npm
  • Language: JavaScript (with TypeScript definitions)
  • Installation: npm install eventemitter3

Core Imports

const 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>();

Basic Usage

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();

Key Differences from Node.js EventEmitter

  • Contextual emission: Optional context parameter for listeners (eliminates fn.bind)
  • Performance optimized: Micro-optimized for high-frequency event handling
  • Removed features: No domain support, no error event throwing, no newListener/removeListener events
  • Different behavior: removeListener removes ALL matching listeners, not just the first

Capabilities

EventEmitter Constructor

Creates a new EventEmitter instance.

/**
 * Creates a new EventEmitter instance
 */
function EventEmitter();

// TypeScript generic version
class EventEmitter<EventTypes = string | symbol, Context = any> {
  constructor();
}

Event Listener Management

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);

Event Emission

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); // true

Event Introspection

Query 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]

Static Properties

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); // true

TypeScript Support

EventEmitter3 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 timestamp

Error Handling

EventEmitter3 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, handled

Performance Considerations

EventEmitter3 is optimized for high-performance scenarios:

  • Argument optimization: Special handling for 1-6 arguments to avoid arguments object
  • Single vs multiple listeners: Different code paths for single and multiple listeners
  • Context binding: Built-in context support eliminates fn.bind() overhead
  • ECMAScript 3: Compatible with older environments while maintaining performance
// 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

docs

index.md

tile.json