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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@6pm/emit

v1.0.0

Published

Screaming fast event emitter, with Symbol support

Readme

6pm/emit

Version npm Build Status Coverage Status

A zero dependency event emitter with lazy initialisation, zero memory and cpu initial state, and full support for Symbol event types!

Installation

Add @6pm/emit to your project via npm.

$ npm install @6pm/emit --save

Testing

First grab a local clone of the github repo.

$ git clone https://github.com/6pm-js/emit.git
$ cd emit

The run the test suite:

$ npm test

Or use istanbul to produce a coverage report.

$ npm run cover

A note on ES2015

@6pm/emit is written using ES2015 features, and as such is directly compatible only with Node versions >= 4.0.0, or recent evergreen browsers.

In theory, Babel or Traceur could be used to transpile for compatibility with considerably older JavaScript engines - if required.

The @6pm/emit module is also exposed via a ES2015 module, though the NPM package includes a UMD wrapped build in dist/emit.js, suitable for inclusion in evergreen browsers, or directly accessing via require in Node.

When using the UMD wrapped build directly in a web browser, the Emit class is exposed via the global sixpm.emit.Emit.

Usage

Mostly compatible with the core NodeJS EventEmitter, except:

  • addition of explicit context extensions, as defined by eventemitter3
  • removal of the 'uncaught error event throws' behaviour - this is very counterintuitive - throw or emit, pick one, or explicitly do both.
  • removal of the expensive and pointless newListener and removeListener events.
  • Total ignorance of the max listeners setting and its very arbitrary warning.

To turn a class into an event emitter, there are two primary approaches:

  • by extension
  • by prototypical enhancement

By extension

Extending the Emit class provides event emitter capabilities to the sub class.

import { Emit } from '@6pm/emit';

class SomeNewEmitter extends Emit {}

let instance	= new SomeNewEmitter(),
	EVENT		= Symbol('my.event');


instance.on(EVENT, () => { /* Do some work. */ });

instance.emit(EVENT, 1, 2, 3);

By prototypical enhancement

The static Emit.assign() method assigns event emitter capabilities to the target object, which can be a static object, or a class prototype.

Because 6pm/emit is initially stateless, no constructor overloading is required - assigning Just Works™.

import { Emit as EventEmitter } from '@6pm/emit';

class SomeNewEmitter {

	constructor() {
		// Note: no Emit based custom construction required.
	}
}

EventEmitter.assign(SomeNewEmitter.prototype);

let instance = new SomeNewEmitter(),

instance.on('some-event', () => { /* Do some work. */ });

instance.emit('some-event', result, false);

Context enhancement

The following methods support a context being passed as an optional third argument, as a shortcut to avoid the overhead of binding a function to a context - an idea brazenly stolen from eventemitter3.

  • on
  • once
  • off
  • addListener
  • removeListener

So, the following:

someEmitter.on('event', callback, context);

is equivalent to, but considerably faster than:

someEmitter.on('event', callback.bind(context));

Design

@6pm/emit is designed to address a very common design pattern in JavaScript.

Namely, that event emission, and consumption are notably disjoint - libraries typically emit many events, in order to expose complete lifecycles of managed information, but applications rarely consume them all - instead cherry picking a necessary few as required.

Zero initial state

This module assumes no initial event state for any given event emitter, instead augmenting emitters only when listeners are registered for the first time, with a 'fast path' that can make safe assumptions about hidden emitter state.

This means that there is no cpu overhead, or space requirements for event emitters, unless an application actually listens to them.

The trade off is that the augmented 'Fast path' methods require additional space once listeners are registered - but for applications where many objects expose event emitter interfaces, but few are used, this has a significant impact on resource usage, and initialisation performance.

Encapsulated internals

All emitter state is hidden via ES2015 Symbols, to prevent clashes, and provide a degree of encapsulation in the design - though obviously not a perfect approach to preventing information leakage (getOwnPropertySymbols allows peering behind the veil)

  • this is generally safer than using named properties.

Symbol support

Symbols as event types are supported, and explicitly tested for, throughout the module - as a matter of personal preference the effective separation / namespacing and readability of Symbols as events seems like a great approach.

Event production:

import { Emit } from '@6pm/emit';

const START = Symbol('someclass.start.event');

export class SomeClass {

	start() {
		this.emit(START);
	}

}

SomeClass.START = START;

Event consumption:

import { SomeClass } from 'someclass.js';

let instance = SomeClass();

// No potential for event name collision, elegant reference to source of event.
instance.on(SomeClass.START, () => { /* ... */ });

Performance

The primary purpose of this module is to provide a (mostly) Node compatible API, to enforce zero initial state for unsubscribed emitters, to ensure strong Symbol support (due to mixed experiences in alternative libraries), and to use a clean ES2015 code style.

Performance optimisation is a secondary concern, though by folding in the lessons learned by the sterling work of the eventemitter3 team, and then continuing to cut any excesses found, this implementation has become exceptionally efficient - microbenchmarks are a fairly poor measure of real world performance - but if desired, it is fairly trivial to add @6pm/emit to eventemitter3's benchmark suite to asses raw overheads - and the results (to be consumed with a suitable serving of salt) show @6pm/emit as having no particular weaknesses, and achieving the highest performance in around half of the tests.

TODO: Add performance testing and resource monitoring tooling to allow comprehensive testing of this in the wild.

Contributing

All comments, criticisms, PRs, and Issues welcome!

License

Release under the MIT license