npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

events-ex

v2.2.0

Published

Browser-friendly enhanced events most compatible with standard node.js, it's powerful eventable ability.

Downloads

870

Readme

events-ex npm downloads license

Browser-friendly enhanced event emitter ability and class. It's modified from event-emitter mainly. It can add/inject the event-able ability to your any class.

Features

  • Modular Event-able Ability: Inject event capabilities into any class using eventable(MyClass) without forced inheritance.
  • Core Event Enhancements:
    • Bubbling & Interruption: Full support for event propagation and mid-stream cancellation.
    • Listener Ordering: Precise control via the optional index parameter in on() and once().
    • Regex Subscription: Subscribe to multiple events using Regular Expressions.
    • Hook-able System: Intercept and modify event behavior at the core level.
  • Advanced Asynchronous Features (Specific to emitAsync):
    • Configurable Concurrency: Choose between Serial (default) and Parallel execution for async listeners.
    • Result Aggregation: Strategies to gather return values: last (default), first (first success), and collect (all results).
    • Fluent API Proxies: Use .parallel() and .configure() for transient, side-effect-free execution context.
  • Architecture: Rewritten core for improved performance and flexibility while maintaining broad compatibility.
  • Event Utilities: Built-in support for pipe, pipeAsync, unify, allOff, and hasListeners.

Differences

  • Difference with node events

    • broken change: The event supports bubbling and interruption
      • the event object as listener's "this" object:
        • result: If set, the result is returned to the Event Emitter.
        • stopped: If set to true, it prevents the remaining listeners from being executed.
        • target: The Event Emitter object, which was originally the this object.
        • type: triggered event type(name).
        • resolved: (Async only) Indicates if a successful result has been found in first mode.
      • broken change: The emit return the result of listeners's callback function instead of the successful state.
      • broken change: The this object of listeners' callback function is the Event Object instead of the emitter object.
        • The emitter object is put into the target property of the Event Object.
    • Enhanced emitAsync Method (Unique to Async):
      • Sequential (Serial): Executes listeners one-by-one, respecting this.stopped.
      • Concurrent (Parallel): Executes all listeners simultaneously.
      • Result Strategies:
        • last: Returns the result of the final listener (or last to finish).
        • first: Returns the first successful non-undefined result (skips errors).
        • collect: Returns an array of all results in registration order.
    • Fluent Configuration: Use .parallel() or .configure({...}) for one-time customized async emits.
    • Listener APIs: on/once(event: string|RegExp, listener, index?: number)
      • 📌 Index Parameter (Optional): Allows specifying the insertion position in the listener array.
      • 🧪 Regex Event Matching: Listeners can bind to multiple events via regex patterns.
  • Difference with event-emitter

    • broken change: The event supports bubbling and interruption (see above).
    • Adds the defaultMaxListeners class property to keep compatibility with node events.
    • Adds the setMaxListeners method to keep compatibility with node events.
    • Adds error, newListener and removeListener events to keep compatibility with node events.
    • Adds listeners() method to keep compatibility with node events.
    • Adds listenerCount() class method to keep compatibility with node events.
    • Adds async event emitting via emitAsync method.
  • 🔗 Event Piping & Unification:

    • pipe(source, target): Sync event forwarding.
    • pipeAsync(source, target, options): Async forwarding with configurable concurrency and aggregation.
    • unify(emitter1, emitter2): Bi-directional synchronization.

Note: The listener throw error should not broke the notification, but it will emit error(emit('error', error, 'notify', eventName, listener, args)) after notification.

Installation

npm install events-ex

Usage

Extends from EventEmitter class

import {EventEmitter} from 'events-ex';

class MyClass extends EventEmitter {}

Add/Inject the event-able ability to your class directly

import {eventable} from 'events-ex';

class MyClass extends MyRoot {}

// inject the eventable ability to MyClass
eventable(MyClass);

Core Feature: Listener Ordering (Index Parameter)

const ee = new EventEmitter();
ee.on('test', () => console.log('second'), 1);
ee.on('test', () => console.log('first'), 0); // Insert at index 0

ee.emit('test');
// Output:
// first
// second

Core Feature: Regex Subscription

const ee = new EventEmitter();
ee.on(/^user\..*/, function(data) {
  console.log(`Event ${this.type} triggered with`, data);
});

ee.emit('user.login', { id: 1 });
ee.emit('user.logout', { id: 1 });

Core Feature: Bubbling & Interruption

import {EventEmitter, states} from 'events-ex';
import {isObject} from 'util-ex';

class MyDb extends EventEmitter {
  get(key) {
    let result = this.emit('getting', key)
    if(isObject(result)) {
      if (result.state === states.ABORT) return
      if (result.state === states.DONE)  return result.result
    }
    return _get(key)
  }
}

let db = new MyDb
db.on('getting', function(key){
  let result = myGet(key);
  if (result != null) {
    this.result = { state: states.DONE, result: result }
    this.stopped = true // Skip remaining listeners
  } else {
    this.result = { state: states.ABORT };
  }
})

Async-Only Features: Concurrency & Aggregation

These features apply only to the emitAsync method.

const ee = new EventEmitter();
ee.on('task', async () => {
  await sleep(100);
  return 'result 1';
});
ee.on('task', async () => {
  return 'result 2';
});

// 1. Default (Serial): Executes sequentially, returns 'result 2'
const res = await ee.emitAsync('task');

// 2. Parallel + Collect: Executes concurrently, returns ['result 1', 'result 2']
const allResults = await ee.parallel('collect').emitAsync('task');

// 3. Parallel + First: Executes concurrently, returns fastest success ('result 2')
const firstResult = await ee.parallel('first').emitAsync('task');

Advanced Features

Async Concurrency Engine (For emitAsync Only)

| Option | Value | Description | | :--- | :--- | :--- | | asyncMode | 'serial' | (Default) Listeners run one by one. Supports this.stopped. | | | 'parallel' | Listeners run concurrently. this.stopped is ignored. | | resultMode | 'last' | (Default) Returns the result of the last listener (or last to finish). | | | 'first' | Returns the first non-undefined and successful result. Skips errors. | | | 'collect' | Returns an array of all results in registration order. |

Proxy Isolation (Fluent API)

Calling .parallel() or .configure() returns a transient Proxy Object (Object.create(this)), allowing thread-safe, isolated configurations for specific emits.

Safe Injection (AoP Compatibility) & Name Collisions

When injecting event capabilities into an existing object or prototype via wrapEventEmitter(target) or eventable(MyClass), a minimal set of methods is injected to minimize the risk of name collisions:

  • on, once, off
  • emit, emitAsync
  • setEmitterOptions

⚠️ Warning on Name Collisions: If your target object already has methods with these names, they will be overwritten.

Solution: Method Renaming You can use the rename option in eventable to map the emitter methods to custom names on your target:

eventable(MyClass, {
  rename: {
    emitAsync: 'myEmitAsync',
    on: 'addListener'
  }
});
// Now use: inst.myEmitAsync('event')

Full EventEmitter vs. Minimal Injection

  • Standalone: Calling ee() or new EventEmitter() without a target returns a full instance containing all advanced methods (including .parallel(), .configure(), .setMaxListeners(), etc.).
  • Injected: Passing a target to ee(target) or using eventable performs a minimal injection to preserve the target's original footprint. Use setEmitterOptions on the target to access advanced async configurations.

API

eventable(class[, options]) (events-ex/eventable)

Add the event-able ability to the class directly.

  • class: the class to be injected the ability.
  • options (object): optional options
    • include (string[]|string): only these emitter methods will be added to the class
    • exclude (string[]|string): theses emitter methods would not be added to the class
    • methods (object): hooked methods to the class
    • emitterOptions (object): default options for the emitter (e.g., asyncMode, resultMode).
    • rename (object): map the emitter methods to custom names on the class.
      • key: original method name (e.g., 'on', 'emitAsync').
      • value: new method name.

hasListeners(obj[, name]) (events-ex/has-listeners)

import {hasListeners, wrapEventEmitter as ee} from 'events-ex';
var emitter = ee();
var listener = function () {};
hasListeners(emitter); // false
emitter.on('foo', listener);
hasListeners(emitter, 'foo'); // true

pipeAsync(source, target[, name, options]) (events-ex/pipe-async)

Creates an asynchronous pipeline.

  • options.asyncMode: Propagation mode ('serial' | 'parallel').
  • options.resultMode: Aggregation strategy.

setEmitterOptions(options)

Configures instance-wide defaults for asyncMode, resultMode, and maxListeners.