als-event-emitter v5.3.0
als-event-emitter
als-event-emitter
is a lightweight, powerful implementation of an event emitter system, designed to be easy to use and extendable. It supports chaining, returns promises for event result handling, and is compatible with both Node.js and browser environments, providing more flexibility compared to the standard Node.js EventEmitter.
What's New
Version 5.3.0
Event Name in Context:
Every listener now receives the event name as part of the context object ({ name, next, resolve, reject, result }
). This is useful for identifying the event currently being processed, especially when usingonAny
.Group Functionality:
Added support for grouping listeners with thegroup
parameter inon
,once
,onLast
, andonceLast
. Listeners assigned to a group will be executed when any event in that group is emitted. This allows for more organized listener management across related events.- Note: Group functionality does not apply to global listeners (
onAny
,onceAny
).
Example:
const emitter = new EventEmitter(); emitter.on('group1', ({ next }) => { console.log('Group listener'); next(); }); emitter.on('event1', ({ next }) => { console.log('Event 1 listener'); next(); }, { group: 'group1' }); emitter.emit('event1'); // Output: // Group listener // Event 1 listener
- Note: Group functionality does not apply to global listeners (
Installation
npm install als-event-emitter
Basic Usage
const EventEmitter = require('als-event-emitter');
// Create an emitter
const emitter = new EventEmitter();
// Register a listener
emitter.on('data', (payload) => {
console.log('Received data:', payload);
});
// Emit an event
emitter.emit('data', { message: 'Hello World' });
Note: In default mode (
new EventEmitter(true)
),emit
returns a Promise and listeners receive{ next, resolve, reject, result }
. If you passfalse
to the constructor (new EventEmitter(true)
)emit
is synchronous.
Browser usage
<script src="/node_modules/als-event-emitter/emitter.js"></script>
<script>
const emitter = new EventEmitter();
</script>
API Overview
new EventEmitter(chain = true | false)
- Creates a new emitter instance.
- If
chain = true
,emit
becomes async and returns aPromise
. - If
chain = false
,emit
is synchronous.
- If
emitter.on(eventName, listener, options?)
- Adds a listener for
eventName
. - If
chain = true
,listener
receives( { next, resolve, reject, result, name }, ...args )
. options
can include:once
: Executes the listener only once.last
: Ensures the listener runs at the end of the chain.group
: Links the listener to a group. If another event in the same group is emitted, the group listener is also triggered.
emitter.once(eventName, listener)
- Adds a one-time listener for
eventName
.
emitter.off(eventName)
- Removes all listeners for
eventName
.
emitter.removeListener(listener)
- Removes the given
listener
from all events and from the globalanyChain
.
emitter.removeAllListeners()
- Removes all registered listeners from all events (and clears
anyChain
for this instance).
emitter.emit(eventName, ...args)
- Emits the event.
- If
chain = true
, returns aPromise
if at least one of function in chain is async. - If
chain = false
, executes listeners synchronously and returnsundefined
.
emitter.onAny(listener, { once, last })
- Registers a listener that will be called for any event emitted by the instance.
emitter.onceAny(listener)
- One-time version of
onAny
.
emitter.has(eventName)
- Checks if there are any listeners for
eventName
.
Global vs. Instance Listeners
Global (Static) Listeners
EventEmitter.on(...)
,EventEmitter.once(...)
, etc.- These listeners are stored in a global chain (
SmartPromise.chain
) and are shared by allEventEmitter
instances. - Use
EventEmitter.removeAllListeners()
to clear all static/global listeners.
Instance Listeners
emitter.on(...)
,emitter.once(...)
, etc.- Stored in the instance's own map of events.
- Call
emitter.removeAllListeners()
to clear the instance's own listeners (includinganyChain
of that instance).
Advanced Usage
onAny
and onceAny
const emitter = new EventEmitter();
let counter = 0;
// Called for any event
emitter.onAny(() => counter++);
emitter.emit('foo'); // counter = 1
emitter.emit('bar'); // counter = 2
onLast
, onceLast
emitter.onLast('myEvent', ({ next }) => {
console.log('Runs last for myEvent');
next();
});
These functions place the listener at the end of the chain, ensuring it runs after normal listeners.
Grouped Listeners
const emitter = new EventEmitter();
emitter.on('groupA', ({ next }) => {
console.log('Group A listener');
next();
});
emitter.on('eventX', ({ next }) => {
console.log('Event X listener');
next();
}, { group: 'groupA' });
emitter.emit('eventX');
// Output:
// Group A listener
// Event X listener
Behavior with No Registered Event
- If you call
emit('unknownEvent')
and no specific listeners exist for'unknownEvent'
, any global listeners (e.g. viaonAny
,onceAny
) will still fire. - This is helpful if you want to log or debug every event, even unregistered ones.
const emitter = new EventEmitter();
emitter.onAny(() => console.log('A global listener triggered!'));
emitter.emit('doesNotExist'); // Logs: "A global listener triggered!"
Chaining and Promises
- If
chain = true
:
Each listener receives:next(result?)
: Proceed to the next listener in the chain.resolve(value)
: Resolve the chain immediately.reject(error)
: Reject the chain immediately.result
: The value passed from the previous listener’snext(result)
.name
: The name of the current event being processed.
- The final
emit(...)
call returns aPromise
, which resolves or rejects based on the chain’s flow.
const emitter = new EventEmitter(true);
emitter.on('process', ({ next }, data) => {
console.log('Step 1:', data);
next('step1-done');
});
emitter.on('process', ({ resolve, result }) => {
console.log('Step 2:', result);
resolve('All done');
});
emitter.emit('process', 'start-data')
.then(finalValue => console.log('Final:', finalValue));
Concurrent and Multi-Emitter Usage
// Multiple Emitters sharing global listeners
EventEmitter.on(() => console.log('Global Listener'));
const emitter1 = new EventEmitter();
const emitter2 = new EventEmitter();
emitter1.emit('someEvent'); // triggers global listener
emitter2.emit('otherEvent'); // triggers global listener
For concurrency in async mode:
const emitter = new EventEmitter(true);
emitter.on('test', async ({ resolve }, val) => {
// Asynchronous listener
await new Promise(r => setTimeout(r, 100));
resolve(`Done-${val}`);
});
// Fire multiple emits concurrently
Promise.all([
emitter.emit('test', 'X'),
emitter.emit('test', 'Y')
]).then(([resX, resY]) => {
console.log(resX, resY);
// "Done-X", "Done-Y"
});
Backward Incompatibility
Since version 5.0, emit
can return a Promise
, and listener signatures have changed to receive ( { next, resolve, reject, result }, ...args )
in chaining mode. If migrating from older versions, ensure your listeners are updated accordingly.
Examples
Basic Usage
const emitter = new EventEmitter();
emitter.on('data', (payload) => {
console.log('Got data:', payload);
});
emitter.emit('data', { key: 'value' });
Using onceAny
const emitter = new EventEmitter();
let called = 0;
emitter.onceAny(() => {
called++;
console.log('Triggered by any event once');
});
emitter.emit('eventA');
emitter.emit('eventB'); // won’t trigger again
console.log('called =', called); // 1
Using onLast
const emitter = new EventEmitter(true);
emitter.on('myEvent', ({ next }) => {
console.log('First Listener');
next();
});
emitter.onLast('myEvent', ({ next }) => {
console.log('Last Listener');
next();
});
emitter.emit('myEvent').then(() => console.log('All done'));