event-emitter-enhancer
Version:
Enhances the Node.js EventEmitter with extra capabilities.
439 lines (354 loc) • 16.5 kB
Markdown
# event-emitter-enhancer
[](https://www.npmjs.org/package/event-emitter-enhancer) [](https://github.com/sagiegurari/event-emitter-enhancer/actions) [](https://coveralls.io/r/sagiegurari/event-emitter-enhancer) [](https://snyk.io/test/github/sagiegurari/event-emitter-enhancer) [](http://inch-ci.org/github/sagiegurari/event-emitter-enhancer) [](https://github.com/sagiegurari/event-emitter-enhancer/blob/master/LICENSE) [](https://www.npmjs.org/package/event-emitter-enhancer)
> Extends the Node.js events.EventEmitter to provide additional functionality.
* [Overview](#overview)
* [Usage](#usage)
* [on(event, listener)](#usage-on1)
* [on(options)](#usage-on2)
* [once(event, listener)](#usage-once)
* [removeAllListeners](#usage-removeAllListeners)
* [else](#usage-else)
* [suspend](#usage-suspend)
* [elseError](#usage-else-error)
* [emitAsync](#usage-emit-async)
* [onAsync](#usage-on-async)
* [onAny](#usage-on-any)
* [filter](#usage-filter)
* [proxyEvents](#usage-proxyEvents)
* [addNoop](#usage-addNoop)
* [ignoreError](#usage-ignoreError)
* [Installation](#installation)
* [API Documentation](docs/api.md)
* [Contributing](.github/CONTRIBUTING.md)
* [Release History](#history)
* [License](#license)
<a name="overview"></a>
## Overview
This library extends the Node.js events.EventEmitter to provide additional functionality.
<a name="usage"></a>
## Usage
First you must require this library as follows:
```js
var EventEmitterEnhancer = require('event-emitter-enhancer');
```
Next you can either modify the proto of an EventEmiter type class, or extend it to get a new custom type or modify a specific emitter instance.
```js
var EventEmitter = require('events').EventEmitter;
//Get predefined extended version of the events.EventEmitter class (original EventEmitter is not impacted)
var emitter = new EventEmitterEnhancer.EnhancedEventEmitter(); //create a new instance using the new extended class type.
//extend events.EventEmitter class (or any class that has the same interface)
//now you can create instances of the new EnhancedEventEmitter type while events.EventEmitter is not modified/impacted in any way
var EnhancedEventEmitter = EventEmitterEnhancer.extend(EventEmitter); //extend the event emitter class (can be Node.js of some custom event emitter). original base class is not affected.
var emitter = new EnhancedEventEmitter(); //create a new instance using the new extended class type.
//modify the proto of an events.EventEmitter class (or any class that has the same interface)
//now all existing and future instances of the original class are modified to include the new extended capabilities.
EventEmitterEnhancer.modify(EventEmitter); //modify the event emitter class prototype (can be Node.js of some custom event emitter). existing instances are impacted.
var emitter = new EventEmitter(); //create an instance of the original class and automatically get the new extended capabilities.
//modify specific instance to include the extended capabilities (other existing/future instances of that class type are not modified/impacted in any way).
var emitter = new EventEmitter(); //create an instance of an event emitter (can be Node.js of some custom event emitter)
EventEmitterEnhancer.modifyInstance(emitter); //modify the specific instance and add the extended capabilities. the original prototype is not affected.
```
<a name="usage-on1"></a>
<!-- markdownlint-disable MD009 MD031 MD036 -->
### 'emitter.on(event, listener) ⇒ function'
See node.js events.EventEmitter.on.<br>
This function also returns a removeListener function to easily remove the provided listener.
**Example**
```js
const EnhancedEventEmitter = EventEmitterEnhancer.extend(EventEmitter);
const emitter = new EnhancedEventEmitter();
const remove = emitter.on('error', function (error) {
console.error(error);
});
//remove listener (no longer need to keep a reference to the listener function)
remove();
```
<!-- markdownlint-enable MD009 MD031 MD036 -->
<a name="usage-on2"></a>
<!-- markdownlint-disable MD009 MD031 MD036 -->
### 'emitter.on(options) ⇒ function'
Enables more complex on capabilities including providing multiple listeners/event names, timeout the listener and more.<br>
To remove the listener/s, the returned function must be called instead of doing emitter.removeListener(...)
**Example**
```js
const EnhancedEventEmitter = EventEmitterEnhancer.extend(EventEmitter);
const emitter = new EnhancedEventEmitter();
const removeListener = emitter.on({
event: ['error', 'connection-error', 'write-error', 'read-error'], //The event names (can be string for a single event)
listener: [ //The listener callback functions (can be a function instead of an array for a single listener callback)
function firstListener(arg1, arg2) {
//do something
},
function secondListener(arg1, arg2) {
//do something
}
],
async: true, //The callback functions will be called after next tick
timeout: 1500 //All listeners will be removed after the provided timeout (if not provided, listeners can only be removed manually via returned function)
});
//emit any event
emitter.emit('write-error', 1, 2, 3);
//once done, remove all listeners from all events
removeListener();
```
<!-- markdownlint-enable MD009 MD031 MD036 -->
<a name="usage-once"></a>
<!-- markdownlint-disable MD009 MD031 MD036 -->
### 'emitter.once(event, listener) ⇒ function'
See node.js events.EventEmitter.once.<br>
This function also returns a removeListener function to easily remove the provided listener.
**Example**
```js
const EnhancedEventEmitter = EventEmitterEnhancer.extend(EventEmitter);
const emitter = new EnhancedEventEmitter();
const remove = emitter.once('error', function (error) {
console.error(error);
});
//remove listener (no longer need to keep a reference to the listener function)
remove();
```
<!-- markdownlint-enable MD009 MD031 MD036 -->
<a name="usage-removeAllListeners"></a>
<!-- markdownlint-disable MD009 MD031 MD036 -->
### 'emitter.removeAllListeners([event])'
See node.js events.EventEmitter.removeAllListeners.<br>
This function is modified to also accept an array of event names.
**Example**
```js
const EnhancedEventEmitter = EventEmitterEnhancer.extend(EventEmitter);
const emitter = new EnhancedEventEmitter();
//same as the basic removeAllListeners
emitter.removeAllListeners('my-event');
//also supports array of event names
emitter.removeAllListeners(['my-event', 'another-event']);
```
<!-- markdownlint-enable MD009 MD031 MD036 -->
<a name="usage-else"></a>
<!-- markdownlint-disable MD009 MD031 MD036 -->
### 'emitter.else(listener)'
Adds an 'else' listener which will be triggered by all events that do not have a listener currently for them (apart of the special 'error' event).
**Example**
```js
const EnhancedEventEmitter = EventEmitterEnhancer.extend(EventEmitter);
const emitter = new EnhancedEventEmitter();
emitter.else(function onUnhandledEvent(event, arg1, arg2) {
//logic here....
//to remove 'else' listeners, simply use the unelse function
emitter.unelse(this);
});
emitter.emit('test', 1, 2);
```
<!-- markdownlint-enable MD009 MD031 MD036 -->
<a name="usage-suspend"></a>
<!-- markdownlint-disable MD009 MD031 MD036 -->
### 'emitter.suspend(event)'
Suspends all emit calls for the provided event name (including 'else' listeners).<br>
For suspended events, the emit function will simply do nothing ('else' listeners won't be invoked either).
**Example**
```js
const EnhancedEventEmitter = EventEmitterEnhancer.extend(EventEmitter);
const emitter = new EnhancedEventEmitter();
emitter.on('test', function () {
//will never be called
});
emitter.suspended = true; //suspend ALL events (to unsuspend use emitter.suspended = false;)
//or
emitter.suspend('test'); //suspend only 'test' event (to unsuspend use emitter.unsuspend('test');)
emitter.emit('test');
```
<!-- markdownlint-enable MD009 MD031 MD036 -->
<a name="usage-else-error"></a>
<!-- markdownlint-disable MD009 MD031 MD036 -->
### 'emitter.elseError(event)'
In case an event with the provided name is emitted but no listener is attached to it, an error event will emitted by this emitter instance instead.
**Example**
```js
const EnhancedEventEmitter = EventEmitterEnhancer.extend(EventEmitter);
const emitter = new EnhancedEventEmitter();
emitter.on('error', function (error) {
//logic here...
//To remove elseError
emitter.unelseError('test');
});
emitter.elseError('test');
emitter.emit('test');
```
<!-- markdownlint-enable MD009 MD031 MD036 -->
<a name="usage-emit-async"></a>
<!-- markdownlint-disable MD009 MD031 MD036 -->
### 'emitter.emitAsync(event, [...params], [callback])'
Invokes the emit after a timeout to enable calling flow to continue and not block due to event listeners.
**Example**
```js
const EnhancedEventEmitter = EventEmitterEnhancer.extend(EventEmitter);
const emitter = new EnhancedEventEmitter();
emitter.on('test', function onTestEvent(num1, num2) {
//event logic here
});
emitter.emitAsync('test', 1, 2, function onEmitDone(event, num1, num2, emitted) {
//emit callback logic
});
```
<!-- markdownlint-enable MD009 MD031 MD036 -->
<a name="usage-on-async"></a>
<!-- markdownlint-disable MD009 MD031 MD036 -->
### 'emitter.onAsync(event, listener) ⇒ function'
Adds a listener that will be triggered after a timeout during an emit.<br>
This ensures that the provided listener is invoked after all other listeners and that it will not block the emit caller flow.<br>
To remove the listener, the returned function must be called instead of doing emitter.removeListener(...)
**Example**
```js
const EnhancedEventEmitter = EventEmitterEnhancer.extend(EventEmitter);
const emitter = new EnhancedEventEmitter();
emitter.on('test', function onEventSync() {
//sync handle function logic
});
const removeListener = emitter.onAsync('test', function onEventAsync() {
//async handle function logic
});
emitter.emit('test', 1, 2);
//remove the async listener
removeListener();
```
<!-- markdownlint-enable MD009 MD031 MD036 -->
<a name="usage-on-any"></a>
<!-- markdownlint-disable MD009 MD031 MD036 -->
### 'emitter.onAny(events, listener) ⇒ function'
Adds a listener to all provided event names.<br>
To remove the listener, the returned function must be called instead of doing emitter.removeListener(...)
**Example**
```js
const EnhancedEventEmitter = EventEmitterEnhancer.extend(EventEmitter);
const emitter = new EnhancedEventEmitter();
//add same listener to multiple events
const remove = emitter.onAny(['test1', 'test2', 'test3'], function (arg1, arg2, arg3) {
console.log(arg1, arg2, arg3);
});
//remove listener from all events
remove();
```
<!-- markdownlint-enable MD009 MD031 MD036 -->
<a name="usage-filter"></a>
<!-- markdownlint-disable MD009 MD031 MD036 -->
### 'emitter.filter([event], filter) ⇒ function'
Adds a filter that will be triggered before every emit for the provided event type (if no event is provided, than the filter is invoked for all events).<br>
The filter enables to prevent events from reaching the listeners in case some criteria is met.
**Example**
```js
const EnhancedEventEmitter = EventEmitterEnhancer.extend(EventEmitter);
const emitter = new EnhancedEventEmitter();
//add filters for test event only
const removeTestEventFilter = emitter.filter('test', function (event, arg1, arg2) {
if (arg1 && (arg1 > 3)) {
return true; //continue with emit
}
return false; //prevent emit
});
emitter.filter('test', function (event, arg1, arg2) {
if (arg2 && (arg2 < 20)) {
return true; //continue with emit
}
return false; //prevent emit
});
//add global filter for all events
emitter.filter(function (event, arg1, arg2) {
if (arg1 && (arg1 > 5)) {
return true; //continue with emit
}
return false; //prevent emit
});
const removeGlobalArg2Filter = emitter.filter(function (event, arg1, arg2) {
if (arg2 && (arg2 < 18)) {
return true; //continue with emit
}
return false; //prevent emit
});
emitter.on('test', function onTestEvent(arg1, arg2) {
//event logic here...
});
emitter.emit('test', 10, 15);
//remove some filters
removeTestEventFilter();
removeGlobalArg2Filter();
```
<!-- markdownlint-enable MD009 MD031 MD036 -->
<a name="usage-proxyEvents"></a>
<!-- markdownlint-disable MD009 MD031 MD036 -->
### 'emitter.proxyEvents(emitters, events) ⇒ function'
Will setup an event proxy so if any of the requested event/s are fired from the provided emitter/s, they will be triggered by this emitter.
**Example**
```js
const EnhancedEventEmitter = EventEmitterEnhancer.extend(EventEmitter);
const emitter = new EnhancedEventEmitter();
//proxy the 'data' and 'end' events from all sockets
const stop = emitter.proxyEvents(sockets, ['data', 'end']);
//listen to events via emitter
emitter.on('data', onData);
//stop events proxy
stop();
```
<!-- markdownlint-enable MD009 MD031 MD036 -->
<a name="usage-addNoop"></a>
<!-- markdownlint-disable MD009 MD031 MD036 -->
### 'emitter.addNoop(event) ⇒ function'
Adds empty event handler.
**Example**
```js
const EnhancedEventEmitter = EventEmitterEnhancer.extend(EventEmitter);
const emitter = new EnhancedEventEmitter();
//add noop even handler for the 'error' event
const remove = emitter.addNoop('error');
//remove listener
remove();
```
<!-- markdownlint-enable MD009 MD031 MD036 -->
<a name="usage-ignoreError"></a>
<!-- markdownlint-disable MD009 MD031 MD036 -->
### 'emitter.ignoreError()'
Adds empty error event handler to prevent node.js from crashing in case of an error which we do not want/need to handle.<br>
This function will only add a new empty handler in case no other handler is defined for the error event.
**Example**
```js
const EnhancedEventEmitter = EventEmitterEnhancer.extend(EventEmitter);
const emitter = new EnhancedEventEmitter();
//adds empty error handler
emitter.ignoreError();
//emit error will not crash the node.js process
emitter.emit('error', new Error('test'));
```
<!-- markdownlint-enable MD009 MD031 MD036 -->
<a name="installation"></a>
## Installation
In order to use this library, just run the following npm install command:
```sh
npm install --save event-emitter-enhancer
```
## API Documentation
See full docs at: [API Docs](docs/api.md)
## Contributing
See [contributing guide](.github/CONTRIBUTING.md)
<a name="history"></a>
## Release History
| Date | Version | Description |
| ----------- | ------- | ----------- |
| 2020-05-11 | v2.0.0 | Migrate to github actions and upgrade minimal node version |
| 2019-12-06 | v1.1.0 | Support event parent parsing and emit #7 |
| 2018-06-13 | v1.0.57 | Added typescript definition (#5 and #6) |
| 2017-11-03 | v1.0.51 | Added 'addNoop' |
| 2017-10-30 | v1.0.49 | Added 'ignoreError' |
| 2017-10-30 | v1.0.48 | New extended 'removeAllListeners' function |
| 2017-01-16 | v1.0.27 | New extended 'once' function |
| 2017-01-07 | v1.0.25 | New 'proxyEvents' function |
| 2017-01-06 | v1.0.24 | New extended 'on' function |
| 2016-11-11 | v1.0.15 | 'emitAsync' callback is now optional |
| 2015-09-23 | v0.0.44 | Added 'onAny' |
| 2015-04-22 | v0.0.31 | Prevent from multiple enhance of same prototype/instance |
| 2014-12-31 | v0.0.10 | EventEmitter is no longer automatically modified,<br>instead there are 2 ways to extend/modify prototype/modify instance<br>functions exposed by this library. |
| 2014-12-30 | v0.0.9 | Added ability to enhance compatible EventEmitter types |
| 2014-12-29 | v0.0.6 | Added 'filter' |
| 2014-12-28 | v0.0.5 | Added 'onAsync' |
| 2014-12-28 | v0.0.4 | Added 'emitAsync' |
| 2014-12-28 | v0.0.2 | Initial release. |
<a name="license"></a>
## License
Developed by Sagie Gur-Ari and licensed under the Apache 2 open source license.