Skip to content

Latest commit

Β 

History

History
298 lines (212 loc) Β· 6.94 KB

File metadata and controls

298 lines (212 loc) Β· 6.94 KB

PatternEmitter Examples

This directory contains practical examples demonstrating how to use @sfast/pattern-emitter-ts in real-world applications.

πŸš€ Running Examples

Prerequisites

# From the root directory
npm install
npm run build

Run Individual Examples

# Basic usage
npx ts-node example/01-basic.ts

# API routing patterns
npx ts-node example/02-api-routing.ts

# Real-world e-commerce app
npx ts-node example/03-real-world-app.ts

# Advanced features
npx ts-node example/04-advanced-features.ts

# Namespace-based events
npx ts-node example/05-namespace-events.ts

# Performance benchmarks
npx ts-node example/06-benchmarks.ts

πŸ“š Examples Overview

1. Basic Usage (01-basic.ts)

What it demonstrates:

  • String event listeners (exact match)
  • Regex pattern listeners (match multiple events)
  • How multiple patterns can match the same event
  • Listener introspection (listenerCount, eventNames, eventPatterns)

Key concept: Understanding the difference between exact string events and flexible regex patterns.

Run it:

npx ts-node example/01-basic.ts

2. API Routing (02-api-routing.ts)

What it demonstrates:

  • Using PatternEmitter for API-style event routing
  • Combining exact endpoints with pattern-based middleware
  • Request logging, authentication, and analytics patterns
  • Real-world routing statistics

Key concept: How to build a flexible routing system using string + regex patterns.

Use case: REST API handlers, middleware chains, request logging

Run it:

npx ts-node example/02-api-routing.ts

Example pattern:

// Exact endpoint
router.on('request:users:list', () => { /* handler */ });

// Pattern for all user endpoints
router.on(/^request:users:/, () => { /* middleware */ });

// Pattern for all create operations
router.on(/:create$/, () => { /* analytics */ });

3. Real-World Application (03-real-world-app.ts)

What it demonstrates:

  • E-commerce order processing system
  • Multiple systems listening to same events:
    • Order processing
    • Analytics tracking
    • Email notifications
    • Error handling
    • Comprehensive logging
  • Asynchronous event-driven architecture

Key concept: Building a complete application with multiple subsystems communicating via events.

Use case: E-commerce, order management, event-driven microservices

Run it:

npx ts-node example/03-real-world-app.ts

4. Advanced Features (04-advanced-features.ts)

What it demonstrates:

  • once() - Single execution listeners
  • Execution order preservation
  • Dynamic handler registration/removal
  • Listener introspection APIs
  • allListeners getter for complete view
  • Bulk cleanup with removeAllListeners
  • Max listeners configuration (memory leak prevention)

Key concept: Advanced PatternEmitter APIs for production applications.

Run it:

npx ts-node example/04-advanced-features.ts

5. Namespace Events (05-namespace-events.ts)

What it demonstrates:

  • Hierarchical event namespaces (colon-separated)
  • Multi-level pattern matching
  • Microservices communication patterns
  • Namespace best practices

Key concept: Organizing events using namespaces for clean, scalable architecture.

Use case: Large applications, microservices, domain-driven design

Run it:

npx ts-node example/05-namespace-events.ts

Example namespaces:

// Hierarchical organization
events.on('app:user:profile:update', handler);
events.on(/^app:user:/, middleware);
events.on(/^app:/, globalLogger);

// Service-oriented
events.on('service:auth:login', handler);
events.on('service:payment:success', handler);

6. Performance Benchmarks (06-benchmarks.ts)

What it demonstrates:

  • Head-to-head comparison: EventEmitter vs PatternEmitter
  • String event performance (apples to apples)
  • Pattern matching overhead
  • Scaling with many patterns
  • Cache performance
  • Listener registration costs

Key concept: Understanding the performance trade-offs to make informed decisions.

Run it:

npx ts-node example/06-benchmarks.ts

Key findings:

String Events:   ~50-60% overhead vs EventEmitter
Pattern Matching: PatternEmitter exclusive feature
Scalability:     Handles 100+ patterns efficiently
Best Practice:   Use PatternEmitter unless profiling shows bottleneck

🎯 Common Patterns

Pattern 1: Exact Event + Wildcard Pattern

const emitter = new PatternEmitter();

// Exact handler
emitter.on('request', () => {
  console.log('Exact request event');
});

// Wildcard for variations
emitter.on(/^request:/, () => {
  console.log('Any request:* event');
});

emitter.emit('request');          // Only first fires
emitter.emit('request:endpoint1'); // Only second fires

Pattern 2: Multiple Overlapping Patterns

// All match the same event - they all fire
emitter.on('user:login', () => {});        // Exact
emitter.on(/^user:/, () => {});            // Prefix
emitter.on(/login$/, () => {});            // Suffix
emitter.on(/.*/, () => {});                // Everything

emitter.emit('user:login'); // All 4 fire in order

Pattern 3: Namespace Hierarchy

// Broad to specific
emitter.on(/^app:/, () => {});              // Level 1: All app events
emitter.on(/^app:user:/, () => {});         // Level 2: User events
emitter.on('app:user:login', () => {});     // Level 3: Specific action

emitter.emit('app:user:login');  // All 3 fire (hierarchy)

πŸ’‘ Best Practices

βœ… DO

  • Use string events for specific, known events
  • Use regex patterns for categories or middleware
  • Organize events with namespaces (colon-separated)
  • Use once() for one-time initialization events
  • Call removeListener to prevent memory leaks
  • Use listenerCount() to debug listener registration

❌ DON'T

  • Don't use overly complex regex (e.g., /(a|b|c|d|e|f|g|h)/)
  • Don't emit events synchronously in a tight loop without setImmediate
  • Don't forget to remove listeners when components unmount
  • Don't mix event naming conventions (choose one style)

πŸ” Debugging

Check what's registered:

// String events only
console.log(emitter.eventNames());

// Regex patterns only
console.log(emitter.eventPatterns());

// All listeners (unified view)
console.log(emitter.allListeners);

// Specific event
console.log(emitter.listeners('my:event'));
console.log(emitter.listenerCount('my:event'));

Check execution:

// Returns true if any listener fired
const hadListeners = emitter.emit('my:event');
if (!hadListeners) {
  console.log('No listeners for this event!');
}

πŸ“– Further Reading


πŸ’¬ Questions?

Open an issue on GitHub