eventemitter3
Advanced tools
Comparing version
209
index.js
'use strict'; | ||
var has = Object.prototype.hasOwnProperty; | ||
var has = Object.prototype.hasOwnProperty | ||
, prefix = '~'; | ||
/** | ||
* Constructor to create a storage for our `EE` objects. | ||
* An `Events` instance is a plain object whose properties are event names. | ||
* | ||
* @constructor | ||
* @api private | ||
*/ | ||
function Events() {} | ||
// | ||
// We store our EE objects in a plain object whose properties are event names. | ||
// We try to not inherit from `Object.prototype`. In some engines creating an | ||
// instance in this way is faster than calling `Object.create(null)` directly. | ||
// If `Object.create(null)` is not supported we prefix the event names with a | ||
// `~` to make sure that the built-in object properties are not overridden or | ||
// used as an attack vector. | ||
// We also assume that `Object.create(null)` is available when the event name | ||
// is an ES6 Symbol. | ||
// character to make sure that the built-in object properties are not | ||
// overridden or used as an attack vector. | ||
// | ||
var prefix = typeof Object.create !== 'function' ? '~' : false; | ||
if (Object.create) { | ||
Events.prototype = Object.create(null); | ||
// | ||
// This hack is needed because the `__proto__` property is still inherited in | ||
// some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5. | ||
// | ||
if (!new Events().__proto__) prefix = false; | ||
} | ||
/** | ||
* Representation of a single EventEmitter function. | ||
* Representation of a single event listener. | ||
* | ||
* @param {Function} fn Event handler to be called. | ||
* @param {Mixed} context Context for function execution. | ||
* @param {Boolean} [once=false] Only emit once | ||
* @param {Function} fn The listener function. | ||
* @param {Mixed} context The context to invoke the listener with. | ||
* @param {Boolean} [once=false] Specify if the listener is a one-time listener. | ||
* @constructor | ||
* @api private | ||
@@ -30,4 +48,4 @@ */ | ||
/** | ||
* Minimal EventEmitter interface that is molded against the Node.js | ||
* EventEmitter interface. | ||
* Minimal `EventEmitter` interface that is molded against the Node.js | ||
* `EventEmitter` interface. | ||
* | ||
@@ -37,13 +55,8 @@ * @constructor | ||
*/ | ||
function EventEmitter() { /* Nothing to set */ } | ||
function EventEmitter() { | ||
this._events = new Events(); | ||
this._eventsCount = 0; | ||
} | ||
/** | ||
* Hold the assigned EventEmitters by name. | ||
* | ||
* @type {Object} | ||
* @private | ||
*/ | ||
EventEmitter.prototype._events = undefined; | ||
/** | ||
* Return an array listing the events for which the emitter has registered | ||
@@ -56,9 +69,9 @@ * listeners. | ||
EventEmitter.prototype.eventNames = function eventNames() { | ||
var events = this._events | ||
, names = [] | ||
var names = [] | ||
, events | ||
, name; | ||
if (!events) return names; | ||
if (this._eventsCount === 0) return names; | ||
for (name in events) { | ||
for (name in (events = this._events)) { | ||
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name); | ||
@@ -75,6 +88,6 @@ } | ||
/** | ||
* Return a list of assigned event listeners. | ||
* Return the listeners registered for a given event. | ||
* | ||
* @param {String} event The events that should be listed. | ||
* @param {Boolean} exists We only need to know if there are listeners. | ||
* @param {String|Symbol} event The event name. | ||
* @param {Boolean} exists Only check if there are listeners. | ||
* @returns {Array|Boolean} | ||
@@ -85,3 +98,3 @@ * @api public | ||
var evt = prefix ? prefix + event : event | ||
, available = this._events && this._events[evt]; | ||
, available = this._events[evt]; | ||
@@ -100,6 +113,6 @@ if (exists) return !!available; | ||
/** | ||
* Emit an event to all registered event listeners. | ||
* Calls each of the listeners registered for a given event. | ||
* | ||
* @param {String} event The name of the event. | ||
* @returns {Boolean} Indication if we've emitted an event. | ||
* @param {String|Symbol} event The event name. | ||
* @returns {Boolean} `true` if the event had listeners, else `false`. | ||
* @api public | ||
@@ -110,3 +123,3 @@ */ | ||
if (!this._events || !this._events[evt]) return false; | ||
if (!this._events[evt]) return false; | ||
@@ -118,3 +131,3 @@ var listeners = this._events[evt] | ||
if ('function' === typeof listeners.fn) { | ||
if (listeners.fn) { | ||
if (listeners.once) this.removeListener(event, listeners.fn, undefined, true); | ||
@@ -147,2 +160,3 @@ | ||
case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break; | ||
case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break; | ||
default: | ||
@@ -162,7 +176,8 @@ if (!args) for (j = 1, args = new Array(len -1); j < len; j++) { | ||
/** | ||
* Register a new EventListener for the given event. | ||
* Add a listener for a given event. | ||
* | ||
* @param {String} event Name of the event. | ||
* @param {Function} fn Callback function. | ||
* @param {Mixed} [context=this] The context of the function. | ||
* @param {String|Symbol} event The event name. | ||
* @param {Function} fn The listener function. | ||
* @param {Mixed} [context=this] The context to invoke the listener with. | ||
* @returns {EventEmitter} `this`. | ||
* @api public | ||
@@ -174,10 +189,5 @@ */ | ||
if (!this._events) this._events = prefix ? {} : Object.create(null); | ||
if (!this._events[evt]) this._events[evt] = listener; | ||
else { | ||
if (!this._events[evt].fn) this._events[evt].push(listener); | ||
else this._events[evt] = [ | ||
this._events[evt], listener | ||
]; | ||
} | ||
if (!this._events[evt]) this._events[evt] = listener, this._eventsCount++; | ||
else if (!this._events[evt].fn) this._events[evt].push(listener); | ||
else this._events[evt] = [this._events[evt], listener]; | ||
@@ -188,7 +198,8 @@ return this; | ||
/** | ||
* Add an EventListener that's only called once. | ||
* Add a one-time listener for a given event. | ||
* | ||
* @param {String} event Name of the event. | ||
* @param {Function} fn Callback function. | ||
* @param {Mixed} [context=this] The context of the function. | ||
* @param {String|Symbol} event The event name. | ||
* @param {Function} fn The listener function. | ||
* @param {Mixed} [context=this] The context to invoke the listener with. | ||
* @returns {EventEmitter} `this`. | ||
* @api public | ||
@@ -200,10 +211,5 @@ */ | ||
if (!this._events) this._events = prefix ? {} : Object.create(null); | ||
if (!this._events[evt]) this._events[evt] = listener; | ||
else { | ||
if (!this._events[evt].fn) this._events[evt].push(listener); | ||
else this._events[evt] = [ | ||
this._events[evt], listener | ||
]; | ||
} | ||
if (!this._events[evt]) this._events[evt] = listener, this._eventsCount++; | ||
else if (!this._events[evt].fn) this._events[evt].push(listener); | ||
else this._events[evt] = [this._events[evt], listener]; | ||
@@ -214,8 +220,9 @@ return this; | ||
/** | ||
* Remove event listeners. | ||
* Remove the listeners of a given event. | ||
* | ||
* @param {String} event The event we want to remove. | ||
* @param {Function} fn The listener that we need to find. | ||
* @param {Mixed} context Only remove listeners matching this context. | ||
* @param {Boolean} once Only remove once listeners. | ||
* @param {String|Symbol} event The event name. | ||
* @param {Function} fn Only remove the listeners that match this function. | ||
* @param {Mixed} context Only remove the listeners that have this context. | ||
* @param {Boolean} once Only remove one-time listeners. | ||
* @returns {EventEmitter} `this`. | ||
* @api public | ||
@@ -226,36 +233,37 @@ */ | ||
if (!this._events || !this._events[evt]) return this; | ||
if (!this._events[evt]) return this; | ||
if (!fn) { | ||
if (--this._eventsCount === 0) this._events = new Events(); | ||
else delete this._events[evt]; | ||
return this; | ||
} | ||
var listeners = this._events[evt] | ||
, events = []; | ||
var listeners = this._events[evt]; | ||
if (fn) { | ||
if (listeners.fn) { | ||
if (listeners.fn) { | ||
if ( | ||
listeners.fn === fn | ||
&& (!once || listeners.once) | ||
&& (!context || listeners.context === context) | ||
) { | ||
if (--this._eventsCount === 0) this._events = new Events(); | ||
else delete this._events[evt]; | ||
} | ||
} else { | ||
for (var i = 0, events = [], length = listeners.length; i < length; i++) { | ||
if ( | ||
listeners.fn !== fn | ||
|| (once && !listeners.once) | ||
|| (context && listeners.context !== context) | ||
listeners[i].fn !== fn | ||
|| (once && !listeners[i].once) | ||
|| (context && listeners[i].context !== context) | ||
) { | ||
events.push(listeners); | ||
events.push(listeners[i]); | ||
} | ||
} else { | ||
for (var i = 0, length = listeners.length; i < length; i++) { | ||
if ( | ||
listeners[i].fn !== fn | ||
|| (once && !listeners[i].once) | ||
|| (context && listeners[i].context !== context) | ||
) { | ||
events.push(listeners[i]); | ||
} | ||
} | ||
} | ||
} | ||
// | ||
// Reset the array, or remove it completely if we have no more listeners. | ||
// | ||
if (events.length) { | ||
this._events[evt] = events.length === 1 ? events[0] : events; | ||
} else { | ||
delete this._events[evt]; | ||
// | ||
// Reset the array, or remove it completely if we have no more listeners. | ||
// | ||
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events; | ||
else if (--this._eventsCount === 0) this._events = new Events(); | ||
else delete this._events[evt]; | ||
} | ||
@@ -267,12 +275,21 @@ | ||
/** | ||
* Remove all listeners or only the listeners for the specified event. | ||
* Remove all listeners, or those of the specified event. | ||
* | ||
* @param {String} event The event want to remove all listeners for. | ||
* @param {String|Symbol} [event] The event name. | ||
* @returns {EventEmitter} `this`. | ||
* @api public | ||
*/ | ||
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) { | ||
if (!this._events) return this; | ||
var evt; | ||
if (event) delete this._events[prefix ? prefix + event : event]; | ||
else this._events = prefix ? {} : Object.create(null); | ||
if (event) { | ||
evt = prefix ? prefix + event : event; | ||
if (this._events[evt]) { | ||
if (--this._eventsCount === 0) this._events = new Events(); | ||
else delete this._events[evt]; | ||
} | ||
} else { | ||
this._events = new Events(); | ||
this._eventsCount = 0; | ||
} | ||
@@ -279,0 +296,0 @@ return this; |
{ | ||
"name": "eventemitter3", | ||
"version": "1.2.0", | ||
"version": "2.0.0", | ||
"description": "EventEmitter3 focuses on performance while maintaining a Node.js AND browser compatible interface.", | ||
"main": "index.js", | ||
"scripts": { | ||
"benchmark": "find benchmarks/run -name '*.js' -exec benchmarks/start.sh {} \\;", | ||
"test-node": "istanbul cover _mocha --report lcovonly -- test.js", | ||
@@ -41,8 +42,8 @@ "coverage": "istanbul cover _mocha -- test.js", | ||
"devDependencies": { | ||
"assume": "1.3.x", | ||
"assume": "1.4.x", | ||
"istanbul": "0.4.x", | ||
"mocha": "2.4.x", | ||
"mocha": "3.0.x", | ||
"pre-commit": "1.1.x", | ||
"zuul": "3.10.x" | ||
"zuul": "3.11.x" | ||
} | ||
} |
# EventEmitter3 | ||
[](http://browsenpm.org/package/eventemitter3)[](https://travis-ci.org/primus/eventemitter3)[](https://david-dm.org/primus/eventemitter3)[](https://coveralls.io/r/primus/eventemitter3?branch=master)[](https://webchat.freenode.net/?channels=primus) | ||
[](https://www.npmjs.com/package/eventemitter3)[](https://travis-ci.org/primus/eventemitter3)[](https://david-dm.org/primus/eventemitter3)[](https://coveralls.io/r/primus/eventemitter3?branch=master)[](https://webchat.freenode.net/?channels=primus) | ||
@@ -18,7 +18,10 @@ [](https://saucelabs.com/u/eventemitter3) | ||
really just edge cases. | ||
- No `setMaxListeners` and it's pointless memory leak warnings. If you want to | ||
- No `setMaxListeners` and its pointless memory leak warnings. If you want to | ||
add `end` listeners you should be able to do that without modules complaining. | ||
- No `listenerCount` function. Use `EE.listeners(event).length` instead. | ||
- No `listenerCount` method. Use `EE.listeners(event).length` instead. | ||
- Support for custom context for events so there is no need to use `fn.bind`. | ||
- `listeners` method can do existence checking instead of returning only arrays. | ||
- The `listeners` method can do existence checking instead of returning only | ||
arrays. | ||
- The `removeListener` method removes all matching listeners, not only the | ||
first. | ||
@@ -88,4 +91,18 @@ It's a drop in replacement for existing EventEmitters, but just faster. Free | ||
### Tests and benchmarks | ||
This module is well tested. You can run: | ||
- `npm test` to run the tests under Node.js. | ||
- `npm run coverage` to get the code coverage. | ||
- `npm run test-browser` to run the tests in real browsers via Sauce Labs. | ||
We also have a set of benchmarks to compare EventEmitter3 with some available | ||
alternatives. To run the benchmarks run `npm run benchmark`. | ||
Tests and benchmarks are not included in the npm package. If you want to play | ||
with them you have to clone the GitHub repository. | ||
## License | ||
[MIT](LICENSE) |
15048
10.49%261
6.53%107
18.89%