EventEmitter3
A blazing-fast, drop-in EventEmitter for Node.js and browsers
Repository Health
Technical Analysis
EventEmitter3 is a high-performance, standalone EventEmitter implementation designed to be a drop-in replacement for Node.js’s built-in events module. It strips away rarely-used features like domains, the newListener/removeListener meta-events, and setMaxListeners in favor of raw speed, while adding contextual this binding for listeners so consumers don’t need fn.bind.
Written in ECMAScript 3 for maximum compatibility, it runs unmodified in the oldest browsers and Node versions, making it a popular low-level dependency for real-time libraries, game engines, and UI frameworks such as PixiJS and Socket.IO/Primus.
What You Get
- A Node.js-compatible EventEmitter API (
on,once,emit,off,listeners,eventNames) usable in both Node and browsers - Contextual listener binding via a
contextargument, avoiding the overhead ofFunction.prototype.bind - An ES3-compatible implementation that runs in legacy browsers and old Node versions without polyfills
- TypeScript type definitions (
index.d.ts) plus both CommonJS (index.js) and native ESM (index.mjs) builds
Common Use Cases
- Powering internal pub/sub in real-time transport libraries like Socket.IO and Primus
- Driving event systems in rendering/game engines such as PixiJS
- Providing lightweight state-change notifications inside UI component libraries
- Replacing Node’s built-in EventEmitter in performance-sensitive server code
Under The Hood
Architecture — EventEmitter3 is a single ~330-line module (index.js) built around three small constructors: Events (a null-prototype map of event name to listener), EE (a wrapper holding a listener function, its bound context, and a once flag), and the public EventEmitter class that owns an Events instance. To sidestep prototype-pollution and shadowing of built-in Object.prototype members, event storage uses Object.create(null) where available, falling back to a ~ name-prefixing trick on engines without it (detected once at module load, not per-call). emit special-cases 0-6 argument counts with unrolled function calls before falling back to Function.prototype.apply for more, trading code size for call-path speed.
Tech Stack — Zero runtime dependencies; published as plain ECMAScript 3 so it works unmodified in ancient browsers and Node releases. The package.json exports map serves index.d.ts (types), index.mjs (ESM), and index.js (CJs) from a single source tree. Rollup + @rollup/plugin-terser produce a minified UMD bundle for the dist/ CDN build, generated only at prepublishOnly time (not committed to the repo).
Code Quality — Tests live in test/test.js (CJS, run via Mocha) and a parallel test/test.mjs (ESM entry point), using the assume assertion library; c8 collects V8-native coverage with both lcov and text reporters wired into npm test. The source carries consistent JSDoc annotations on every method (@param, @returns, @private), and naming is terse but consistent with the Node.js events module it mirrors, which keeps the diff between the two APIs easy to reason about.
API Design — The public surface deliberately mirrors Node’s built-in EventEmitter (on, once, emit, removeListener, removeAllListeners, listeners, eventNames, listenerCount) so it’s usable as a near drop-in replacement with no relearning cost. Its one notable extension — passing a context object as an extra argument to on/once/removeListener — removes the common need for fn.bind(this) at call sites, a small but genuinely ergonomic addition documented directly in the README with runnable examples.
Used by 12 apps in this directory
Readur
Bookmarks Archiving · File Storage · Knowledge Management
A self-hosted document management system that OCRs, indexes, and makes every PDF, scan, and Office file instantly searchable.
Rocket.Chat
Team Chat
The secure, self-hosted team communications platform for organizations that cannot compromise on data sovereignty.
SigNoz
Analytics · Monitoring
Self-host your entire observability stack — logs, metrics, traces, and LLM monitoring — in one OpenTelemetry-native platform, without the Datadog bill.