futoin-asyncevent
v2.3.7
Published
FutoIn AsyncEvent - FTN15 compliant event emitter
Downloads
37
Maintainers
Readme
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
Extra details
- 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 intarget[EventEmitter.SYM_EVENT_EMITTER]
property.- Almost no pollution to target object
- Very fast lookup
on()
,off()
,once()
andemit()
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 usesarray#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() {
// dynamically extend & pre-configure allowed events
$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);
// Basic event operation
// ---------------------
o.on('event_one', h);
o.off('event_one', h);
o.once('event_two', () => console.log('Second'));
o.someFunc();
// Advanced
// --------
// instanceof hook (ES6)
(o instanceof $asyncevent.EventEmitter) === true
// update max listeners warning threshold
$asyncevent.EventEmitter.setMaxListeners( o, 16 );
// Additional events in derived class
// ----------------------------------
class DerivedClass extends FirstClass {
constructor() {
super();
// Transparently checks, if EventEmitter has been already
// registered with other events
$asyncevent(this, ['another_event']);
}
}
// Fail on duplicate event names
// ----------------------------------
class FailClass extends FirstClass {
constructor() {
super();
// It's not allowed to override already registered event for
// safety reasons.
$asyncevent(this, ['event_one']);
}
}
API documentation
The concept is described in FutoIn specification: FTN15: Native Event API v1.x
Classes
Members
Constants
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.