Event emitter for modular designs.
Design goals:
- minimalistic extendable API;
- support for application profiling and testing on both front- and back-end;
- implement all this with minimum amount of code.
NB: The release 1.0 conveniently supports using instance methods as event handlers. Enhanced API makes preventing memory leaks much easier.
> npm install eventist
or
> bower install eventist
Take a look at and play with code samples and Special Patterns below.
Call synchronously the handlers registered for the event.
When a handler returns anything else than undefined
, emit() will return
the same value immediately, perhaps leaving some handlers untouched.
Handlers will be invoked starting from the most recently registered one. Setting or removing handlers during the emit loop has no effect on handling the current event.
- event string.
- arguments are optional and can be of any type.
- Returns:
undefined
or the value returned by any handler.
Put event into queue to be called asynchronously on the next timer tick. If callback is supplied, then Eventist will invoke it with the following argument values:
null
or the exception value if one was caught;- return value return value from event processing;
- array containing the
event
and allarguments
.
If callback is not supplied, then exception from processing will not be caught.
- callback is
function(*,*,Array<*>)
. - event string.
- arguments are optional and can be of any type.
- Returns: instance of itself for chaining.
- Throws: any exception from event processing if
callback
is missing.
Register a handler (function or method) for event. No checks for duplicates.
- event string.
- handler function that will be called with arguments supplied to emit(). See return value handling above.
- instance object instance.
- Returns: instance of itself for chaining.
- Throws:
TypeError
upon illegal argument type.
Same as on(), but the handler will be removed right after it gets called.
Remove previously registered handler for the event
, if found.
If duplicate registrations were made, only the last one will be undone.
TypeError
exception will be thrown if event is not a string.
- event string.
- handler function previously registered via on() or once().
or
true
to remove all handlers for given event. - instance object instance.
- Returns: instance of itself for chaining.
- Throws:
TypeError
if event is not a string.
NOTE: The instance argument will be supplied to handler as thisArg, but it can be any value.
Remove handlers, which are methods of given instance, if found.
- instance object instance.
- Returns: instance of itself for chaining.
- Throws:
TypeError
exception will be thrown if instance is not an object or isnull
.
The following methods are intended for debugging and production code should not use those. This API or parts of it may be deprecated soon.
Set the hook callback function. Callback hook will be called by emit() before any of the handlers. Callback hook function may modify the arguments array in any way, before it will be applied to handlers. Calling the method with falsey argument will remove the hook callback.
- callback function receiving array of all arguments supplied to emit();
- Returns: previous hook callback or null;
- Throws:
TypeError
ifcallback
is not falsey and is not a function.
Sets a callback to be called in the end of every call of emit() or send()
with arguments event
, count
and args
,
count being a number of handlers actually
executed on particular event. Otherwise, it is similar to hook() method.
- callback function receiving count of handlers invoked and the event itself;
- Returns: previous hook callback or null;
- Throws:
TypeError
ifcallback
is not falsey and is not a function.
Return recursion depth of current event. Value 0 means that emit() is not active.
Eventist makes no checks or restrictions about event recursion.
- Returns: number.
Return a dictionary object of handler counts for event types. May be useful for debugging.
- Returns: Object.
Actually call the handler function. You may want to override this method for debugging/profiling purposes. This method should not be called directly.
- handler function previously registered via on() or once().
- arguments array of those supplied to emit().
- event as supplied to emit().
- Returns: anything from handler.
If code like eventist.on(someEvent, objectsMethod, objectInstance)
is executed, then eventist.unplug(objectInstance)
should be called before
discarding the object instance. Failure to do so will result in memory leak.
Before v1.0 the only way to use instance method as event handler was to use closures, which resulted in ugly code.
This feature comes handy for fishing out possible event name typo errors.
var eventist = new Eventist();
eventist.reporter (function (count, event) {
count || console.log('UNHANDLED:', event);
});
...
var eventist = new Eventist();
var original = eventist.execute;
eventist.execute = function(cb, args, event) {
var response = original.call(eventist, ev, cb);
if(response === THIS && event === THAT){
cb = 0; // set a breakpoint here
}
return response;
}
The following example is probably not very useful by itself, but the code
before and after emit
invocation can do something more interesting,
like maintaining profiling dictionaries etc.
var eventist = new Eventist();
var count = 0, time = 0;
var emit = eventist.emit;
eventist.emit = function(ev) {
var t0 = getCurrentTime();
var res = emit.apply(eventist, arguments);
time += getCurrentTime() - t0;
count += 1;
return res;
}
Emitting a new event right from a handler may result in deeply nested events, puzzling execution track potentially hard-to-spot bugs. In such cases send() may be better choice. In the following example, the return value will be forwarded with some other data via event2 and the callback will run after this has been processed.
var handler1 = function() {
var res1 = doMyProcessing();
eventist.send(function(err, res2, args) {
// Process if necessary...
},
'event2', res1, somethingMore...);
return res1; // If necessary...
};
If we do not need result processing or we do not need to wait until our response gets processed, then the "If necessary..." lines can be omitted.
The same tests can be run for different environments using the following commands:
> gulp test # --> reports/coverage/node/
> karma start # --> reports/coverage/browser-amd/
> karma start --direct # --> reports/coverage/browser/
- Olical/EventEmitter - similar, but slightly different project with beautiful code. I spotted this one when I was already on final.