Browse Source

events: _events to object and undefined not null

By making sure the _events is always an object there is one less check
that needs to be performed by emit.

Use undefined instead of null. typeof checks are a lot faster than
isArray.

There are a few places where the this._events check cannot be removed
because it is possible for the user to call those methods after using
utils.extend to create their own EventEmitter, but before it has
actually been instantiated.
v0.9.12-release
Trevor Norris 12 years ago
committed by isaacs
parent
commit
4f7f8bbdf8
  1. 29
      lib/events.js
  2. 3
      src/node.cc
  3. 2
      test/simple/test-event-emitter-listeners-side-effects.js
  4. 4
      test/simple/test-event-emitter-set-max-listeners-side-effects.js

29
lib/events.js

@ -19,7 +19,6 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE. // USE OR OTHER DEALINGS IN THE SOFTWARE.
var isArray = Array.isArray;
var domain; var domain;
exports.usingDomains = false; exports.usingDomains = false;
@ -33,7 +32,7 @@ function EventEmitter() {
this.domain = domain.active; this.domain = domain.active;
} }
} }
this._events = this._events || null; this._events = this._events || {};
this._maxListeners = this._maxListeners || defaultMaxListeners; this._maxListeners = this._maxListeners || defaultMaxListeners;
} }
exports.EventEmitter = EventEmitter; exports.EventEmitter = EventEmitter;
@ -57,8 +56,9 @@ var PROCESS;
EventEmitter.prototype.emit = function(type) { EventEmitter.prototype.emit = function(type) {
// If there is no 'error' event listener then throw. // If there is no 'error' event listener then throw.
if (type === 'error') { if (type === 'error') {
if (!this._events || !this._events.error || if (!this._events.error ||
(isArray(this._events.error) && !this._events.error.length)) { (typeof this._events.error === 'object' &&
!this._events.error.length)) {
if (this.domain) { if (this.domain) {
var er = arguments[1]; var er = arguments[1];
er.domainEmitter = this; er.domainEmitter = this;
@ -77,7 +77,6 @@ EventEmitter.prototype.emit = function(type) {
} }
} }
if (!this._events) return false;
var handler = this._events[type]; var handler = this._events[type];
if (!handler) return false; if (!handler) return false;
@ -111,7 +110,7 @@ EventEmitter.prototype.emit = function(type) {
} }
return true; return true;
} else if (isArray(handler)) { } else if (typeof handler === 'object') {
if (this.domain) { if (this.domain) {
PROCESS = PROCESS || process; PROCESS = PROCESS || process;
if (this !== PROCESS) { if (this !== PROCESS) {
@ -153,7 +152,7 @@ EventEmitter.prototype.addListener = function(type, listener) {
if (!this._events[type]) { if (!this._events[type]) {
// Optimize the case of one listener. Don't need the extra array object. // Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener; this._events[type] = listener;
} else if (isArray(this._events[type])) { } else if (typeof this._events[type] === 'object') {
// If we've already got an array, just append. // If we've already got an array, just append.
this._events[type].push(listener); this._events[type].push(listener);
@ -165,7 +164,7 @@ EventEmitter.prototype.addListener = function(type, listener) {
} }
// Check for listener leak // Check for listener leak
if (isArray(this._events[type]) && !this._events[type].warned) { if (typeof this._events[type] === 'object' && !this._events[type].warned) {
var m; var m;
m = this._maxListeners; m = this._maxListeners;
@ -219,11 +218,11 @@ EventEmitter.prototype.removeListener = function(type, listener) {
if (list === listener || if (list === listener ||
(typeof list.listener === 'function' && list.listener === listener)) { (typeof list.listener === 'function' && list.listener === listener)) {
this._events[type] = null; this._events[type] = undefined;
if (this._events.removeListener) if (this._events.removeListener)
this.emit('removeListener', type, listener); this.emit('removeListener', type, listener);
} else if (isArray(list)) { } else if (typeof list === 'object') {
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
if (list[i] === listener || if (list[i] === listener ||
(list[i].listener && list[i].listener === listener)) { (list[i].listener && list[i].listener === listener)) {
@ -237,7 +236,7 @@ EventEmitter.prototype.removeListener = function(type, listener) {
if (list.length === 1) { if (list.length === 1) {
list.length = 0; list.length = 0;
this._events[type] = null; this._events[type] = undefined;
} else { } else {
list.splice(position, 1); list.splice(position, 1);
} }
@ -261,9 +260,9 @@ EventEmitter.prototype.removeAllListeners = function(type) {
// not listening for removeListener, no need to emit // not listening for removeListener, no need to emit
if (!this._events.removeListener) { if (!this._events.removeListener) {
if (arguments.length === 0) if (arguments.length === 0)
this._events = null; this._events = {};
else if (this._events[type]) else if (this._events[type])
this._events[type] = null; this._events[type] = undefined;
return this; return this;
} }
@ -274,7 +273,7 @@ EventEmitter.prototype.removeAllListeners = function(type) {
this.removeAllListeners(key); this.removeAllListeners(key);
} }
this.removeAllListeners('removeListener'); this.removeAllListeners('removeListener');
this._events = null; this._events = {};
return this; return this;
} }
@ -287,7 +286,7 @@ EventEmitter.prototype.removeAllListeners = function(type) {
while (listeners.length) while (listeners.length)
this.removeListener(type, listeners[listeners.length - 1]); this.removeListener(type, listeners[listeners.length - 1]);
} }
this._events[type] = null; this._events[type] = undefined;
return this; return this;
}; };

3
src/node.cc

@ -2477,6 +2477,9 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {
3); 3);
process->Set(String::NewSymbol("_tickInfoBox"), info_box); process->Set(String::NewSymbol("_tickInfoBox"), info_box);
// pre-set _events object for faster emit checks
process->Set(String::NewSymbol("_events"), Object::New());
return process; return process;
} }

2
test/simple/test-event-emitter-listeners-side-effects.js

@ -33,7 +33,7 @@ var fl; // foo listeners
fl = e.listeners('foo'); fl = e.listeners('foo');
assert(Array.isArray(fl)); assert(Array.isArray(fl));
assert(fl.length === 0); assert(fl.length === 0);
assert.equal(e._events, null); assert.deepEqual(e._events, {});
e.on('foo', assert.fail); e.on('foo', assert.fail);
fl = e.listeners('foo'); fl = e.listeners('foo');

4
test/simple/test-event-emitter-set-max-listeners-side-effects.js

@ -25,6 +25,6 @@ var events = require('events');
var e = new events.EventEmitter; var e = new events.EventEmitter;
assert.strictEqual(e._events, null); assert.deepEqual(e._events, {});
e.setMaxListeners(5); e.setMaxListeners(5);
assert.strictEqual(e._events, null); assert.deepEqual(e._events, {});

Loading…
Cancel
Save