events: stricter prop & variable checks for perf

Replace truthy/falsey checks of _events and _events[type] with
comparisons to undefined for better performance:

events/ee-add-remove.js n=250000    5.30 %    *** 4.260028e-07
events/ee-emit.js n=2000000         4.18 %    *** 1.026649e-05

This has a knock-on effect on modules that use lots of events, e.g.:

http2/headers.js nheaders=0 n=1000  2.60 %    *** 0.000298338

PR-URL: https://github.com/nodejs/node/pull/16212
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
This commit is contained in:
Anatoli Papirovski 2017-10-14 20:49:01 -04:00
parent 6d4c68523d
commit f61cc15c6a
No known key found for this signature in database
GPG Key ID: 614E2E1ABEB4B2C0

View File

@ -78,7 +78,8 @@ EventEmitter.init = function() {
} }
} }
if (!this._events || this._events === Object.getPrototypeOf(this)._events) { if (this._events === undefined ||
this._events === Object.getPrototypeOf(this)._events) {
this._events = Object.create(null); this._events = Object.create(null);
this._eventsCount = 0; this._eventsCount = 0;
} }
@ -170,8 +171,8 @@ EventEmitter.prototype.emit = function emit(type) {
var doError = (type === 'error'); var doError = (type === 'error');
events = this._events; events = this._events;
if (events) if (events !== undefined)
doError = (doError && events.error == null); doError = (doError && events.error === undefined);
else if (!doError) else if (!doError)
return false; return false;
@ -181,7 +182,7 @@ EventEmitter.prototype.emit = function emit(type) {
if (doError) { if (doError) {
if (arguments.length > 1) if (arguments.length > 1)
er = arguments[1]; er = arguments[1];
if (domain) { if (domain !== null && domain !== undefined) {
if (!er) { if (!er) {
const errors = lazyErrors(); const errors = lazyErrors();
er = new errors.Error('ERR_UNHANDLED_ERROR'); er = new errors.Error('ERR_UNHANDLED_ERROR');
@ -206,10 +207,10 @@ EventEmitter.prototype.emit = function emit(type) {
handler = events[type]; handler = events[type];
if (!handler) if (handler === undefined)
return false; return false;
if (domain && this !== process) { if (domain !== null && domain !== undefined && this !== process) {
domain.enter(); domain.enter();
needDomainExit = true; needDomainExit = true;
} }
@ -255,13 +256,13 @@ function _addListener(target, type, listener, prepend) {
} }
events = target._events; events = target._events;
if (!events) { if (events === undefined) {
events = target._events = Object.create(null); events = target._events = Object.create(null);
target._eventsCount = 0; target._eventsCount = 0;
} else { } else {
// To avoid recursion in the case that type === "newListener"! Before // To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener". // adding it to the listeners, first emit "newListener".
if (events.newListener) { if (events.newListener !== undefined) {
target.emit('newListener', type, target.emit('newListener', type,
listener.listener ? listener.listener : listener); listener.listener ? listener.listener : listener);
@ -272,7 +273,7 @@ function _addListener(target, type, listener, prepend) {
existing = events[type]; existing = events[type];
} }
if (!existing) { if (existing === undefined) {
// 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.
existing = events[type] = listener; existing = events[type] = listener;
++target._eventsCount; ++target._eventsCount;
@ -384,11 +385,11 @@ EventEmitter.prototype.removeListener =
} }
events = this._events; events = this._events;
if (!events) if (events === undefined)
return this; return this;
list = events[type]; list = events[type];
if (!list) if (list === undefined)
return this; return this;
if (list === listener || list.listener === listener) { if (list === listener || list.listener === listener) {
@ -424,7 +425,7 @@ EventEmitter.prototype.removeListener =
if (list.length === 1) if (list.length === 1)
events[type] = list[0]; events[type] = list[0];
if (events.removeListener) if (events.removeListener !== undefined)
this.emit('removeListener', type, originalListener || listener); this.emit('removeListener', type, originalListener || listener);
} }
@ -436,15 +437,15 @@ EventEmitter.prototype.removeAllListeners =
var listeners, events, i; var listeners, events, i;
events = this._events; events = this._events;
if (!events) if (events === undefined)
return this; return this;
// not listening for removeListener, no need to emit // not listening for removeListener, no need to emit
if (!events.removeListener) { if (events.removeListener === undefined) {
if (arguments.length === 0) { if (arguments.length === 0) {
this._events = Object.create(null); this._events = Object.create(null);
this._eventsCount = 0; this._eventsCount = 0;
} else if (events[type]) { } else if (events[type] !== undefined) {
if (--this._eventsCount === 0) if (--this._eventsCount === 0)
this._events = Object.create(null); this._events = Object.create(null);
else else
@ -472,7 +473,7 @@ EventEmitter.prototype.removeAllListeners =
if (typeof listeners === 'function') { if (typeof listeners === 'function') {
this.removeListener(type, listeners); this.removeListener(type, listeners);
} else if (listeners) { } else if (listeners !== undefined) {
// LIFO order // LIFO order
for (i = listeners.length - 1; i >= 0; i--) { for (i = listeners.length - 1; i >= 0; i--) {
this.removeListener(type, listeners[i]); this.removeListener(type, listeners[i]);
@ -487,11 +488,11 @@ EventEmitter.prototype.listeners = function listeners(type) {
var ret; var ret;
var events = this._events; var events = this._events;
if (!events) if (events === undefined)
ret = []; ret = [];
else { else {
evlistener = events[type]; evlistener = events[type];
if (!evlistener) if (evlistener === undefined)
ret = []; ret = [];
else if (typeof evlistener === 'function') else if (typeof evlistener === 'function')
ret = [evlistener.listener || evlistener]; ret = [evlistener.listener || evlistener];
@ -514,12 +515,12 @@ EventEmitter.prototype.listenerCount = listenerCount;
function listenerCount(type) { function listenerCount(type) {
const events = this._events; const events = this._events;
if (events) { if (events !== undefined) {
const evlistener = events[type]; const evlistener = events[type];
if (typeof evlistener === 'function') { if (typeof evlistener === 'function') {
return 1; return 1;
} else if (evlistener) { } else if (evlistener !== undefined) {
return evlistener.length; return evlistener.length;
} }
} }