Stability: 3 - Stable
About
Implementation of a well-known event emitter pattern, but with fundamental requirement: execute
all events asynchronously - there must be no emitter functionality function frames on the stack.
All other event emitters implementations are synchronous - they call handlers when event is emitted.
As there is a known security-related timing problem of setTimeout()
calls in browser, enhanced
event loop is used from futoin-asyncsteps module.
Second important feature - strict check of allowed event types.
Documentation --> FutoIn Guide
Reference implementation of:
FTN15: Native Event API
Version: 1.1
Spec: FTN15: Native Event API v1.x
Author: Andrey Galkin
- ActiveAsyncTool from AsyncSteps is used for each handler.
- All exceptions can be traced runtime-defined way - exceptions are forced to be re-thrown in dedicated event loop call
- Performance of setImmediate() with workaround for security-related slowdown in browsers.
- A single immediate is used for regular execution of event.
EventEmitter
instance is hidden in target[EventEmitter.SYM_EVENT_EMITTER]
property.
- Almost no pollution to target object
- Very fast lookup
on()
, off()
, once()
and emit()
are defined as properties which proxy call
- At the moment,
emit()
uses ES6 spread oprerator (e.g. ...args
):
- the approach which is around 4 times faster in Node.js compared to old ES5 browsers
- there are no optimizations done yet (no significant case so far)
- Each event has own "on" and "once" arrays:
- performance over memory tradeoff
- "once" array is simply discarded and replaced after first use, if there are any handlers
on()
/once()
calls are cheapoff()
call uses array#filter()
- the same handler can be added more than once, but it gets removed on first
off()
call off()
removes handler both from "on" and "once" arrays
- Async event dispatch considerations:
once( 'event', () => o.once( 'event', ... ) )
approach IS NOT SAFE as it leads to missed events!- avoid emitting too many events in a synchronous loop - event handlers get scheduled, but not executed!
Installation for Node.js
Command line:
$ npm install futoin-asyncevent --save
or
$ yarn add futoin-asyncevent
Hint: checkout FutoIn CID for all tools setup.
Browser installation
Pre-built ES5 CJS modules are available under es5/
. These modules
can be used with webpack
without transpiler - default "browser" entry point
points to ES5 version.
Webpack dists are also available under dist/
folder, but their usage should be limited
to sites without build process.
Warning: older browsers should use dist/polyfill-asyncevent.js
for Symbol
.
The following globals are available:
- $asyncevent - global reference to futoin-asyncevent module
- futoin - global namespace-like object for name clashing cases
- futoin.$asyncevent - another reference to futoin-asyncevent module
- futoin.EventEmitter - global reference to futoin-asyncevent.EventEmitter class
Examples
Simple steps
const $asyncevent = require('futoin-asyncevent');
class FirstClass {
constructor() {
$asyncevent(this, ['event_one', 'event_two', 'event_three']);
}
someFunc() {
this.emit( 'event_one', 'some_arg', 2, true );
}
}
const o = new FirstClass();
const h = (a, b, c) => console.log(a, b, c);
o.on('event_one', h);
o.off('event_one', h);
o.once('event_two', () => console.log('Second'));
o.someFunc();
(o instanceof $asyncevent.EventEmitter) === true
$asyncevent.EventEmitter.setMaxListeners( o, 16 );
class DerivedClass extends FirstClass {
constructor() {
super();
$asyncevent(this, ['another_event']);
}
}
class FailClass extends FirstClass {
constructor() {
super();
$asyncevent(this, ['event_one']);
}
}
API documentation
The concept is described in FutoIn specification: FTN15: Native Event API v1.x
Classes
- EventEmitter
Asynchronous Event Emitter.
Members
- $asyncevent
window.$asyncevent - browser-only reference to futoin-asyncsteps module
- $asyncevent
window.FutoIn.$asyncevent - browser-only reference to futoin-asyncsteps module
- EventEmitter
window.futoin.EventEmitter - browser-only reference to futoin-asyncsteps.EventEmitter
Constants
- $asyncevent
Attach event emitter properties to object. Call it in c-tor.
EventEmitter
Asynchronous Event Emitter.
Kind: global class
Note: Please avoid inheriting it, use EventEmitter.attach() instead!
eventEmitter.on(evt, handler)
Attach event handler.
Kind: instance method of EventEmitter
Param | Type | Description |
---|
evt | string | preconfigured event name |
handler | callable | async event handler |
eventEmitter.once(evt, handler)
Attach once-only event handler.
Kind: instance method of EventEmitter
Param | Type | Description |
---|
evt | string | preconfigured event name |
handler | callable | async event handler |
eventEmitter.off(evt, handler)
Remove event handler.
Kind: instance method of EventEmitter
Param | Type | Description |
---|
evt | string | preconfigured event name |
handler | callable | async event handler |
eventEmitter.emit(evt)
Emit async event.
Kind: instance method of EventEmitter
Param | Type | Description |
---|
evt | string | event name |
EventEmitter.attach(instance, allowed_events, max_listeners)
Attach event emitter to any instance
Kind: static method of EventEmitter
Param | Type | Default | Description |
---|
instance | object | | target object |
allowed_events | array | | list of allowed event names |
max_listeners | integer | 8 | maximum allowed handlers per event name |
EventEmitter.setMaxListeners(instance, max_listeners)
Dynamically update max listener count
Kind: static method of EventEmitter
Param | Type | Description |
---|
instance | object | target object |
max_listeners | integer | maximum allowed handlers per event name |
$asyncevent
window.$asyncevent - browser-only reference to futoin-asyncsteps module
Kind: global variable
$asyncevent.EventEmitter
Reference to EventEmitter class
Kind: static property of $asyncevent
$asyncevent
window.FutoIn.$asyncevent - browser-only reference to futoin-asyncsteps module
Kind: global variable
$asyncevent.EventEmitter
Reference to EventEmitter class
Kind: static property of $asyncevent
EventEmitter
window.futoin.EventEmitter - browser-only reference to futoin-asyncsteps.EventEmitter
Kind: global variable
eventEmitter.on(evt, handler)
Attach event handler.
Kind: instance method of EventEmitter
Param | Type | Description |
---|
evt | string | preconfigured event name |
handler | callable | async event handler |
eventEmitter.once(evt, handler)
Attach once-only event handler.
Kind: instance method of EventEmitter
Param | Type | Description |
---|
evt | string | preconfigured event name |
handler | callable | async event handler |
eventEmitter.off(evt, handler)
Remove event handler.
Kind: instance method of EventEmitter
Param | Type | Description |
---|
evt | string | preconfigured event name |
handler | callable | async event handler |
eventEmitter.emit(evt)
Emit async event.
Kind: instance method of EventEmitter
Param | Type | Description |
---|
evt | string | event name |
EventEmitter.attach(instance, allowed_events, max_listeners)
Attach event emitter to any instance
Kind: static method of EventEmitter
Param | Type | Default | Description |
---|
instance | object | | target object |
allowed_events | array | | list of allowed event names |
max_listeners | integer | 8 | maximum allowed handlers per event name |
EventEmitter.setMaxListeners(instance, max_listeners)
Dynamically update max listener count
Kind: static method of EventEmitter
Param | Type | Description |
---|
instance | object | target object |
max_listeners | integer | maximum allowed handlers per event name |
$asyncevent
Attach event emitter properties to object. Call it in c-tor.
Kind: global constant
See: EventEmitter.attach()
$asyncevent.EventEmitter
Reference to EventEmitter class
Kind: static property of $asyncevent
documented by jsdoc-to-markdown.