EventEmitter
without a base class or string event names. Supports adding, removing, and one-shot listeners.
var listeners = require('listeners')
var onEvent = listeners()
onEvent(function (time) {
console.log("the time is", time)
})
onEvent.once(function (arg1, arg2) {
console.log('the time is', time, '[once]')
})
setInterval(function () {
onEvent.notify(new Date())
}, 1000)
Node's built-in EventEmitter allows you to name events using arbitrary strings. While this is convenient for module authors, it presents great difficulty for module readers: humans must search documentation (or module source code) to learn the names of events and the data they might emit, and static-analysis tools are unable to determine whether a given event name is valid or not.
Furthermore, the flexibility afforded by emit(eventName)
is rarely used in
practice, with most event emitters using only a small set of constant event
names (e.g. 'data'
, 'error'
and 'end'
).
This module implements the core functionality of EventEmitter
--maintaining a
list of callbacks to be called when a given event is triggered-- using
higher-order functions and closures rather than a base class and collection of
methods. Favouring composition over inheritance, EventEmitter-
instances can
be attached to an object using statically analyzable names.
Consider this simple Counter
example:
inherits(Counter, EventEmitter)
function Counter (value) {
EventEmitter.call(this)
this.value = value || 0
}
Counter.prototype.inc = function () {
this.emit('change', ++this.value)
}
Counter.prototype.dec = function () {
this.emit('change', --this.value)
}
The above EventEmitter
instance only ever emits one event: 'change'
. We can
instead write this using EventEmitter-
to be:
function Counter (value) {
this.onChange = eeMinus()
this.value = value || 0
}
Counter.prototype.inc = function () {
this.onChange.notify(++this.value)
}
Counter.prototype.dec = function () {
this.onChange.notify(--this.value)
}
The benefit here is that we now have a well defined interface for static analysis and documentation tools to look at.