events: use spread function param in emit

With recent changes in V8, it is now as performant or faster to use
spread parameter within EventEmitter.prototype.emit, especially
in cases where looping over arguments is required.

events/ee-emit.js n=2000000               4.40 %    *** 1.505543e-06
events/ee-emit-1-arg.js n=2000000         2.16 %    *** 2.434584e-10
events/ee-emit-2-args.js n=2000000        1.05 %     ** 0.001764852
events/ee-emit-3-args.js n=2000000        2.18 %    *** 3.234954e-08
events/ee-emit-6-args.js n=2000000       17.17 %    *** 1.298702e-103
events/ee-emit-10-args.js n=2000000      17.14 %    *** 1.144958e-97

This has a knock-on effect for modules that use events extensively,
such as http2:

http2/headers.js nheaders=0 n=1000        2.10 %    *** 6.792106e-11

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-15 00:44:47 -04:00
parent fd166a8759
commit d5fb78982a
No known key found for this signature in database
GPG Key ID: 614E2E1ABEB4B2C0

View File

@ -162,23 +162,22 @@ function emitMany(handler, isFn, self, args) {
}
}
EventEmitter.prototype.emit = function emit(type) {
var er, handler, len, args, i, events, domain;
var needDomainExit = false;
var doError = (type === 'error');
EventEmitter.prototype.emit = function emit(type, ...args) {
let doError = (type === 'error');
events = this._events;
const events = this._events;
if (events !== undefined)
doError = (doError && events.error === undefined);
else if (!doError)
return false;
domain = this.domain;
const domain = this.domain;
// If there is no 'error' event listener then throw.
if (doError) {
if (arguments.length > 1)
er = arguments[1];
let er;
if (args.length > 0)
er = args[0];
if (domain !== null && domain !== undefined) {
if (!er) {
const errors = lazyErrors();
@ -202,37 +201,32 @@ EventEmitter.prototype.emit = function emit(type) {
return false;
}
handler = events[type];
const handler = events[type];
if (handler === undefined)
return false;
let needDomainExit = false;
if (domain !== null && domain !== undefined && this !== process) {
domain.enter();
needDomainExit = true;
}
var isFn = typeof handler === 'function';
len = arguments.length;
switch (len) {
// fast cases
case 1:
const isFn = typeof handler === 'function';
switch (args.length) {
case 0:
emitNone(handler, isFn, this);
break;
case 1:
emitOne(handler, isFn, this, args[0]);
break;
case 2:
emitOne(handler, isFn, this, arguments[1]);
emitTwo(handler, isFn, this, args[0], args[1]);
break;
case 3:
emitTwo(handler, isFn, this, arguments[1], arguments[2]);
emitThree(handler, isFn, this, args[0], args[1], args[2]);
break;
case 4:
emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
break;
// slower
default:
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
emitMany(handler, isFn, this, args);
}