From 4f7f8bbdf891f1ba59c620b45c257b61dc65807a Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Tue, 26 Feb 2013 09:47:36 -0800 Subject: [PATCH] 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. --- lib/events.js | 29 +++++++++---------- src/node.cc | 3 ++ ...st-event-emitter-listeners-side-effects.js | 2 +- ...-emitter-set-max-listeners-side-effects.js | 4 +-- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/lib/events.js b/lib/events.js index 7e19491e9f..45577c8c60 100644 --- a/lib/events.js +++ b/lib/events.js @@ -19,7 +19,6 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -var isArray = Array.isArray; var domain; exports.usingDomains = false; @@ -33,7 +32,7 @@ function EventEmitter() { this.domain = domain.active; } } - this._events = this._events || null; + this._events = this._events || {}; this._maxListeners = this._maxListeners || defaultMaxListeners; } exports.EventEmitter = EventEmitter; @@ -57,8 +56,9 @@ var PROCESS; EventEmitter.prototype.emit = function(type) { // If there is no 'error' event listener then throw. if (type === 'error') { - if (!this._events || !this._events.error || - (isArray(this._events.error) && !this._events.error.length)) { + if (!this._events.error || + (typeof this._events.error === 'object' && + !this._events.error.length)) { if (this.domain) { var er = arguments[1]; er.domainEmitter = this; @@ -77,7 +77,6 @@ EventEmitter.prototype.emit = function(type) { } } - if (!this._events) return false; var handler = this._events[type]; if (!handler) return false; @@ -111,7 +110,7 @@ EventEmitter.prototype.emit = function(type) { } return true; - } else if (isArray(handler)) { + } else if (typeof handler === 'object') { if (this.domain) { PROCESS = PROCESS || process; if (this !== PROCESS) { @@ -153,7 +152,7 @@ EventEmitter.prototype.addListener = function(type, listener) { if (!this._events[type]) { // Optimize the case of one listener. Don't need the extra array object. 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. this._events[type].push(listener); @@ -165,7 +164,7 @@ EventEmitter.prototype.addListener = function(type, listener) { } // 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; m = this._maxListeners; @@ -219,11 +218,11 @@ EventEmitter.prototype.removeListener = function(type, listener) { if (list === listener || (typeof list.listener === 'function' && list.listener === listener)) { - this._events[type] = null; + this._events[type] = undefined; if (this._events.removeListener) this.emit('removeListener', type, listener); - } else if (isArray(list)) { + } else if (typeof list === 'object') { for (i = 0; i < length; i++) { if (list[i] === listener || (list[i].listener && list[i].listener === listener)) { @@ -237,7 +236,7 @@ EventEmitter.prototype.removeListener = function(type, listener) { if (list.length === 1) { list.length = 0; - this._events[type] = null; + this._events[type] = undefined; } else { list.splice(position, 1); } @@ -261,9 +260,9 @@ EventEmitter.prototype.removeAllListeners = function(type) { // not listening for removeListener, no need to emit if (!this._events.removeListener) { if (arguments.length === 0) - this._events = null; + this._events = {}; else if (this._events[type]) - this._events[type] = null; + this._events[type] = undefined; return this; } @@ -274,7 +273,7 @@ EventEmitter.prototype.removeAllListeners = function(type) { this.removeAllListeners(key); } this.removeAllListeners('removeListener'); - this._events = null; + this._events = {}; return this; } @@ -287,7 +286,7 @@ EventEmitter.prototype.removeAllListeners = function(type) { while (listeners.length) this.removeListener(type, listeners[listeners.length - 1]); } - this._events[type] = null; + this._events[type] = undefined; return this; }; diff --git a/src/node.cc b/src/node.cc index 847ebaffb2..25354e9d84 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2477,6 +2477,9 @@ Handle SetupProcessObject(int argc, char *argv[]) { 3); process->Set(String::NewSymbol("_tickInfoBox"), info_box); + // pre-set _events object for faster emit checks + process->Set(String::NewSymbol("_events"), Object::New()); + return process; } diff --git a/test/simple/test-event-emitter-listeners-side-effects.js b/test/simple/test-event-emitter-listeners-side-effects.js index 92a5bef97c..c6218e0598 100644 --- a/test/simple/test-event-emitter-listeners-side-effects.js +++ b/test/simple/test-event-emitter-listeners-side-effects.js @@ -33,7 +33,7 @@ var fl; // foo listeners fl = e.listeners('foo'); assert(Array.isArray(fl)); assert(fl.length === 0); -assert.equal(e._events, null); +assert.deepEqual(e._events, {}); e.on('foo', assert.fail); fl = e.listeners('foo'); diff --git a/test/simple/test-event-emitter-set-max-listeners-side-effects.js b/test/simple/test-event-emitter-set-max-listeners-side-effects.js index a50479784a..604129796e 100644 --- a/test/simple/test-event-emitter-set-max-listeners-side-effects.js +++ b/test/simple/test-event-emitter-set-max-listeners-side-effects.js @@ -25,6 +25,6 @@ var events = require('events'); var e = new events.EventEmitter; -assert.strictEqual(e._events, null); +assert.deepEqual(e._events, {}); e.setMaxListeners(5); -assert.strictEqual(e._events, null); +assert.deepEqual(e._events, {});