A lightweight ; only 341 Bytes (bundle size), might be the worlds fastest, microtask-based asynchronous and synchronous event emitter for JavaScript/TypeScript. Also for REACT! Check the benchmark results below!
COZY stands for Compact, On-point, Zero-overhead, Yet-powerful.
A fine-tailored ecosystem of TypeScript libraries designed for your everyday needs—lightweight, efficient, and built to get the job done. No bloat, just pure performance. 🚀
- v.1.4.0: React Support; CozyEvent has now react support! (Special thanks to jeangq24 )
- v.1.2.0: Performance improvement; 22x faster than v.1.1.0 (see the benchmark below)
- v1.1.0: Performance improvement; 4x faster than version v1.0 (see the benchmark bellow)
- Supports both synchronous and asynchronous (microtask-based) event emission.
- Allows multiple listeners per event.
- Provides once event handling.
- Enables removal of specific or all event listeners.
- Designed for performance with a minimal footprint.
You can install CozyEvent via npm or yarn:
npm install cozyevent@latest-light
or
yarn add cozyevent@latest-light
npm install cozyevent@latest-react
or
yarn add cozyevent@latest-react
import { CozyEvent } from 'cozyevent';
const { CozyEvent } = require('cozyevent');
const eventEmitter = new CozyEvent();
Registers an event listener that triggers every time the event is emitted.
eventEmitter.on('message', (msg) => {
console.log(`Received: ${msg}`);
});
Registers an event listener that triggers only once.
eventEmitter.once('init', () => {
console.log('Initialization complete!');
});
Emits a sync event.
eventEmitter.emit('message', 'Hello, World!');
Emits an async event emission using microtasks.
eventEmitter.emitAsync('data', { id: 1, name: 'John Doe' });
Removes a specific event listener.
const handler = (msg) => console.log(msg);
eventEmitter.on('chat', handler);
eventEmitter.off('chat', handler);
Removes all listeners for a specific event or all events if no event is specified. This method replaces the previous destroy
method, as it now handles the same functionality.
eventEmitter.removeAllListeners('chat');
You can extend CozyEvent
in your own class to create a custom event-driven system:
class SomeClass extends CozyEvent {
doSomething() {
console.log('Doing something...');
this.emit('done', 'Task completed');
}
}
const instance = new SomeClass();
instance.on('done', (message) => {
console.log(`Received: ${message}`);
});
instance.doSomething();
Deprecated: This method has been replaced by
removeAllListeners()
. UseremoveAllListeners()
to achieve the same functionality.
// Deprecated
eventEmitter.destroy();
// Recommended
eventEmitter.removeAllListeners();
CozyEvent provides seamless React integration through:
CozyEventProvider
(Context Provider)useCozyEvent
(Custom Hook)- Centralized Instance Registry
This allows declarative event management in React applications, supporting multiple instances and automatic event cleanup.
npm install cozyevent
or
yarn add cozyevent
A React context provider that supplies a CozyEvent
instance to child components.
instance?
: CustomCozyEvent
instance (defaults to global instance).children
: Child components with event access.id?
: Identifier for managing multiple instances (default:'default'
).
import { CozyEventProvider } from 'cozyevent';
const App = () => (
<CozyEventProvider>
<MyComponent />
</CozyEventProvider>
);
A hook for subscribing to events from the nearest CozyEventProvider
.
eventName
: Event name (required).callback
: Function executed when the event is emitted (required).options?
:namespace?
: Scope event subscription.id?
: Target a specificCozyEventProvider
.
CozyEvent
instance.
import { useCozyEvent } from 'cozyevent';
const EventListener = () => {
useCozyEvent('message', (data) => {
console.log('Received:', data);
});
return <div>Listening...</div>;
};
Manages multiple CozyEvent
instances globally.
Registers an instance.
Note: You don't need to manually register the instance before creating the
CozyEventProvider
. The provider will automatically register the instance with the givenid
.
import { registerCozyEventInstance, CozyEvent } from 'cozyevent';
const emitter = new CozyEvent();
registerCozyEventInstance('custom', emitter);
Retrieves an instance.
import { getCozyEventInstanceById } from 'cozyevent';
const emitter = getCozyEventInstanceById('custom');
emitter?.emit('event', 'Hello!');
import React from 'react';
import { CozyEventProvider, useCozyEvent } from 'cozyevent';
const EventEmitter = () => {
const emitEvent = () => {
getCozyEventInstanceById('default')?.emit('test-event', 'Hello!');
};
return <button onClick={emitEvent}>Emit Event</button>;
};
const EventListener = () => {
useCozyEvent('test-event', (message) => alert(message));
return <div>Listening for events...</div>;
};
const App = () => (
<CozyEventProvider>
<EventEmitter />
<EventListener />
</CozyEventProvider>
);
export default App;
useCozyEvent('user-login', (data) => console.log('Logged in:', data), {
namespace: 'auth',
});
const App = () => (
<>
<CozyEventProvider id="auth">
<AuthModule />
</CozyEventProvider>
<CozyEventProvider id="notifications">
<NotificationModule />
</CozyEventProvider>
</>
);
const AuthModule = () => {
useCozyEvent('login', (data) => console.log('User:', data), { id: 'auth' });
return <div>Auth Module</div>;
};
const NotificationModule = () => {
useCozyEvent('new-message', (msg) => console.log('Message:', msg), {
id: 'notifications',
});
return <div>Notifications</div>;
};
If CozyEventProvider
is missing, useCozyEvent
falls back to the global instance.
useCozyEvent('global-event', (data) => console.log('Global event:', data));
✅ Use meaningful event names to avoid conflicts.
✅ Leverage namespaces for better organization.
✅ Let useCozyEvent
handle cleanup (no manual unsubscriptions).
✅ Use custom instances for modularity.
✅ Assign id
to providers for debugging.
✅ Utilize the registry for easy instance management.
The following are the benchmark results for 1,000,000 listeners (from fastest to slowest):
Library | Operation | Rate (ops/sec) | Variability (%) | Runs Sampled |
---|---|---|---|---|
cozyEvent | emit | 4,095 | ±0.80% | 94 |
tseep | emit | 3,587 | ±1.85% | 91 |
braintree-event-emitter | emit | 3,431 | ±3.43% | 85 |
emitix | emit | 461 | ±2.41% | 84 |
eventemitter3 | emit | 180 | ±1.89% | 83 |
eventemitter2 | emit | 150 | ±2.45% | 76 |
node-event-emitter | emit | 120 | ±4.22% | 70 |
protobufjs-eventemitter | emit | 119 | ±0.70% | 77 |
event-emitter | emit | 91.98 | ±3.25% | 68 |
Library | ops/sec | Variability (%) | Runs Sampled |
---|---|---|---|
cozyEvent | 7,048,823 | ±23.01% | 44 |
tseep | 6,699,486 | ±22.93% | 58 |
eventemitter2 | 4,759,473 | ±32.42% | 48 |
eventemitter3 | 2,760,536 | ±34.21% | 47 |
braintree-event-emitter | 2,493,323 | ±25.56% | 34 |
event-emitter | 1,578,055 | ±29.92% | 35 |
protobufjs-eventemitter | 1,533,468 | ±62.37% | 18 |
emitix | 886,668 | ±65.42% | 20 |
node-event-emitter | 116,289 | ±12.12% | 18 |
Library | ops/sec | Variability (%) | Runs Sampled |
---|---|---|---|
tseep | 7,025,903 | ±19.21% | 49 |
cozyEvent | 3,161,190 | ±36.82% | 35 |
eventemitter2 | 2,349,562 | ±28.37% | 42 |
eventemitter3 | 2,247,466 | ±32.67% | 42 |
event-emitter | 293,539 | ±115.29% | 17 |
node-event-emitter | 69,743 | ±77.57% | 18 |
emitix | 27,619 | ±50.74% | 6 |
Library | ops/sec | Variability (%) | Runs Sampled |
---|---|---|---|
tseep | 241,358,834 | ±0.43% | 96 |
eventemitter3 | 237,546,830 | ±0.78% | 90 |
emitix | 86,382,491 | ±1.77% | 93 |
protobufjs-eventemitter | 84,816,381 | ±0.54% | 99 |
cozyEvent | 64,156,580 | ±1.30% | 89 |
node-event-emitter | 53,750,923 | ±2.40% | 91 |
eventemitter2 | 47,492,910 | ±1.99% | 86 |
braintree-event-emitter | 37,476,993 | ±0.49% | 96 |
event-emitter | 34,195,978 | ±0.99% | 96 |
Library | ops/sec | Variability (%) | Runs Sampled |
---|---|---|---|
cozyEvent | 174,527,998 | ±0.86% | 89 |
eventemitter3 | 160,803,376 | ±2.56% | 91 |
eventemitter2 | 104,917,857 | ±2.26% | 94 |
node-event-emitter | 26,451,753 | ±3.37% | 90 |
tseep | 8,722,096 | ±2.12% | 93 |
Copyright (c) 2025 Mehmet Ergin Turk
Licensed under the MIT license. See the LICENSE file for details.
(Twitter/x: @papa_alpha_papa),
(Mastodon: @papa_alpha_papa)
(Bluesky: @erginturk.bsky.social)