events-intercept
Version:
event interceptors - like middleware for EventEmitter
117 lines (77 loc) • 4.71 kB
Markdown
#`events-intercept`
[](https://travis-ci.org/brandonhorst/events-intercept)
[](https://coveralls.io/r/brandonhorst/events-intercept?branch=master)
The node [EventEmitter](http://nodejs.org/api/events.html) is very powerful. However, at times it could be valuable to intercept events before they reach their handlers, to modify the data, or emit other events. That's a job for `event-intercept`.
##Installation
```sh
npm install events-intercept
```
##Standalone Usage
The module contains a constructor, `EventEmitter`, which inherits from the standard node `events.EventEmitter`.
var EventEmitter = require('events-intercept').EventEmitter;
var emitter = new EventEmitter();
In our application, we have an object that will emit a `data` event, and pass it a single argument.
emitter.emit('data', 'myData')
It is very easy to listen for this event and handle it
emitter.on('data', function(arg) {
console.log(arg);
}); //logs 'myData'
However, we want to intercept that event and modify the data. We can do that by setting an `interceptor` with `intercept(event, interceptor)`. It is passed all arguments that would be passed to the emitter, as well as a standard node callback. In this case, let's just add a prefix on to the data.
emitter.intercept('data', function(arg, done) {
return done(null, 'intercepted ' + arg);
});
This code will be executed before the handler, and the new argument will be passed on to the handler appropriately.
emitter.emit('data', 'some other data');
//logs 'intercepted some other data'
If multiple interceptors are added to a single event, they will be called in the order that they are added, like [async.waterfall](https://github.com/caolan/async#waterfall).
Here's that sample code all together. Of course, `intercept` supports proper function chaining.
var eventsIntercept = require('events-intercept');
var emitter = new eventsIntercept.EventEmitter();
emitter
.on('data', function(arg) {
console.log(arg);
}).intercept('data', function(arg, done) {
return done(null, 'intercepted ' + arg);
}).emit('data', 'myData');
//logs 'intercepted myData'
Please see `test/intercept.js` for more complete samples.
##Calling Separate Events
There may be times when you want to intercept one event and call another. Luckily, all `intercept` handlers are called with the `EventEmitter` as the `this` context, so you can `emit` events yourself.
emitter.intercept('data', function(done) {
this
.emit('otherData')
.emit('thirdData');
return done(null);
});
//emits 'data', 'otherData', and 'thirdData'
Remember, `emit`ting an event that you are `intercept`ing will cause a loop, so be careful.
In fact, an `intercept`or do not need to call the callback at all, which means that the event that was `intercept`ed will never be called at all.
emitter.intercept('data', function(done) {
this
.emit('otherData')
.emit('thirdData');
});
//emits 'otherData' and 'thirdData' but not 'data'
##Utilities
`events-intercept` supports all of the useful utilities that the standard `EventEmitter` supports:
* `interceptors(type)` returns an array of all interceptors (functions) for the given type.
* `removeInterceptor(type, interceptor)` removes an interceptor of a given type. You must pass in the interceptor function.
* `removeAllInterceptors(type)` removes all interceptors for a given type.
* `removeAllInterceptors()` removes all interceptors. Will remove the `removeInterceptor` event last, so they will all get triggered.
* the EventEmitter will throw a warning if more than 10 interceptors are added to a single event, as this could represent a memory leak. `setMaxInterceptors(n)` allows you to change that. Set it to 0 for no limit.
All of these are demonstrated in the tests.
##Patching
Of course, many EventEmitters that you have the pleasure of using will not have the foresight to use `event-intercept`. Thankfully, Javascript is awesome, it's possible to monkey patch the interception capabilities onto an existing object. Just call
var events = require('events');
var eventsIntercept = require('events-intercept');
var emitter = new events.EventEmitter();
eventsIntercept.patch(emitter)
emitter
.on('data', function(arg) {
console.log(arg);
}).intercept('data', function(arg, done) {
return done(null, 'intercepted ' + arg);
}).emit('data', 'myData');
//logs 'intercepted myData'
Now, you should be able to call `intercept` on the standard `EventEmitter`.
This is also shown in `test/intercept.js`.