or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

async-iteration.mddebug-system.mdevent-emission.mdevent-subscription.mdindex.mdutilities.md
tile.json

utilities.mddocs/

Utilities

Helper methods for managing listeners, binding methods, and getting emitter state information.

Capabilities

Remove Event Listeners

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 function

Clear All Listeners

Remove 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 events

Count Active Listeners

Get 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 up

Bind Methods to Objects

Bind 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 directly

Advanced Usage Patterns

Listener Management

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

Conditional Listener Cleanup

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

Method Binding Patterns

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

Memory Management

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