events: remove emit micro-optimizations
With improvements in V8, using separate emit functions is no longer necessary and can instead be replaced by the spread operator. improvement confidence p.value events/ee-emit.js n=2000000 2.98 % 0.09852489 events/ee-emit-2-args.js n=2000000 4.19 % *** 0.0001914216 events/ee-emit-6-args.js n=2000000 61.69 % *** 6.611964e-35 events/ee-emit-diff-args.js n=2000000 -0.36 % 0.305069 events/ee-once.js n=20000000 6.42 % *** 1.27831e-06 PR-URL: https://github.com/nodejs/node/pull/16869 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: Bryan English <bryan@bryanenglish.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Timothy Gu <timothygu99@gmail.com> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com> Reviewed-By: Benedikt Meurer <benedikt.meurer@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Brian White <mscdex@mscdex.net>
This commit is contained in:
parent
6b351e92dc
commit
f44f18a857
@ -1,20 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
const common = require('../common.js');
|
|
||||||
const EventEmitter = require('events').EventEmitter;
|
|
||||||
|
|
||||||
const bench = common.createBenchmark(main, { n: [2e6] });
|
|
||||||
|
|
||||||
function main(conf) {
|
|
||||||
const n = conf.n | 0;
|
|
||||||
|
|
||||||
const ee = new EventEmitter();
|
|
||||||
|
|
||||||
for (var k = 0; k < 10; k += 1)
|
|
||||||
ee.on('dummy', function() {});
|
|
||||||
|
|
||||||
bench.start();
|
|
||||||
for (var i = 0; i < n; i += 1) {
|
|
||||||
ee.emit('dummy', 5, true);
|
|
||||||
}
|
|
||||||
bench.end(n);
|
|
||||||
}
|
|
@ -2,19 +2,51 @@
|
|||||||
const common = require('../common.js');
|
const common = require('../common.js');
|
||||||
const EventEmitter = require('events').EventEmitter;
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
const bench = common.createBenchmark(main, { n: [2e6] });
|
const bench = common.createBenchmark(main, {
|
||||||
|
n: [2e6],
|
||||||
|
argc: [0, 2, 4, 10],
|
||||||
|
listeners: [1, 5, 10],
|
||||||
|
});
|
||||||
|
|
||||||
function main(conf) {
|
function main(conf) {
|
||||||
const n = conf.n | 0;
|
const n = conf.n | 0;
|
||||||
|
const argc = conf.argc | 0;
|
||||||
|
const listeners = Math.max(conf.listeners | 0, 1);
|
||||||
|
|
||||||
const ee = new EventEmitter();
|
const ee = new EventEmitter();
|
||||||
|
|
||||||
for (var k = 0; k < 10; k += 1)
|
for (var k = 0; k < listeners; k += 1)
|
||||||
ee.on('dummy', function() {});
|
ee.on('dummy', function() {});
|
||||||
|
|
||||||
|
var i;
|
||||||
|
switch (argc) {
|
||||||
|
case 2:
|
||||||
bench.start();
|
bench.start();
|
||||||
for (var i = 0; i < n; i += 1) {
|
for (i = 0; i < n; i += 1) {
|
||||||
|
ee.emit('dummy', true, 5);
|
||||||
|
}
|
||||||
|
bench.end(n);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
bench.start();
|
||||||
|
for (i = 0; i < n; i += 1) {
|
||||||
|
ee.emit('dummy', true, 5, 10, false);
|
||||||
|
}
|
||||||
|
bench.end(n);
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
bench.start();
|
||||||
|
for (i = 0; i < n; i += 1) {
|
||||||
|
ee.emit('dummy', true, 5, 10, false, 5, 'string', true, false, 11, 20);
|
||||||
|
}
|
||||||
|
bench.end(n);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bench.start();
|
||||||
|
for (i = 0; i < n; i += 1) {
|
||||||
ee.emit('dummy');
|
ee.emit('dummy');
|
||||||
}
|
}
|
||||||
bench.end(n);
|
bench.end(n);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,63 +105,6 @@ EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
|
|||||||
return $getMaxListeners(this);
|
return $getMaxListeners(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
// These standalone emit* functions are used to optimize calling of event
|
|
||||||
// handlers for fast cases because emit() itself often has a variable number of
|
|
||||||
// arguments and can be deoptimized because of that. These functions always have
|
|
||||||
// the same number of arguments and thus do not get deoptimized, so the code
|
|
||||||
// inside them can execute faster.
|
|
||||||
function emitNone(handler, isFn, self) {
|
|
||||||
if (isFn)
|
|
||||||
handler.call(self);
|
|
||||||
else {
|
|
||||||
var len = handler.length;
|
|
||||||
var listeners = arrayClone(handler, len);
|
|
||||||
for (var i = 0; i < len; ++i)
|
|
||||||
listeners[i].call(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function emitOne(handler, isFn, self, arg1) {
|
|
||||||
if (isFn)
|
|
||||||
handler.call(self, arg1);
|
|
||||||
else {
|
|
||||||
var len = handler.length;
|
|
||||||
var listeners = arrayClone(handler, len);
|
|
||||||
for (var i = 0; i < len; ++i)
|
|
||||||
listeners[i].call(self, arg1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function emitTwo(handler, isFn, self, arg1, arg2) {
|
|
||||||
if (isFn)
|
|
||||||
handler.call(self, arg1, arg2);
|
|
||||||
else {
|
|
||||||
var len = handler.length;
|
|
||||||
var listeners = arrayClone(handler, len);
|
|
||||||
for (var i = 0; i < len; ++i)
|
|
||||||
listeners[i].call(self, arg1, arg2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function emitThree(handler, isFn, self, arg1, arg2, arg3) {
|
|
||||||
if (isFn)
|
|
||||||
handler.call(self, arg1, arg2, arg3);
|
|
||||||
else {
|
|
||||||
var len = handler.length;
|
|
||||||
var listeners = arrayClone(handler, len);
|
|
||||||
for (var i = 0; i < len; ++i)
|
|
||||||
listeners[i].call(self, arg1, arg2, arg3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function emitMany(handler, isFn, self, args) {
|
|
||||||
if (isFn)
|
|
||||||
handler.apply(self, args);
|
|
||||||
else {
|
|
||||||
var len = handler.length;
|
|
||||||
var listeners = arrayClone(handler, len);
|
|
||||||
for (var i = 0; i < len; ++i)
|
|
||||||
listeners[i].apply(self, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EventEmitter.prototype.emit = function emit(type, ...args) {
|
EventEmitter.prototype.emit = function emit(type, ...args) {
|
||||||
let doError = (type === 'error');
|
let doError = (type === 'error');
|
||||||
|
|
||||||
@ -212,22 +155,13 @@ EventEmitter.prototype.emit = function emit(type, ...args) {
|
|||||||
needDomainExit = true;
|
needDomainExit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isFn = typeof handler === 'function';
|
if (typeof handler === 'function') {
|
||||||
switch (args.length) {
|
handler.apply(this, args);
|
||||||
case 0:
|
} else {
|
||||||
emitNone(handler, isFn, this);
|
const len = handler.length;
|
||||||
break;
|
const listeners = arrayClone(handler, len);
|
||||||
case 1:
|
for (var i = 0; i < len; ++i)
|
||||||
emitOne(handler, isFn, this, args[0]);
|
listeners[i].apply(this, args);
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
emitTwo(handler, isFn, this, args[0], args[1]);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
emitThree(handler, isFn, this, args[0], args[1], args[2]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
emitMany(handler, isFn, this, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needDomainExit)
|
if (needDomainExit)
|
||||||
@ -313,23 +247,11 @@ EventEmitter.prototype.prependListener =
|
|||||||
return _addListener(this, type, listener, true);
|
return _addListener(this, type, listener, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
function onceWrapper() {
|
function onceWrapper(...args) {
|
||||||
if (!this.fired) {
|
if (!this.fired) {
|
||||||
this.target.removeListener(this.type, this.wrapFn);
|
this.target.removeListener(this.type, this.wrapFn);
|
||||||
this.fired = true;
|
this.fired = true;
|
||||||
switch (arguments.length) {
|
this.listener.apply(this.target, args);
|
||||||
case 0:
|
|
||||||
return this.listener.call(this.target);
|
|
||||||
case 1:
|
|
||||||
return this.listener.call(this.target, arguments[0]);
|
|
||||||
case 2:
|
|
||||||
return this.listener.call(this.target, arguments[0], arguments[1]);
|
|
||||||
case 3:
|
|
||||||
return this.listener.call(this.target, arguments[0], arguments[1],
|
|
||||||
arguments[2]);
|
|
||||||
default:
|
|
||||||
this.listener.apply(this.target, arguments);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,10 +9,10 @@ SyntaxError: Strict mode code may not include a with statement
|
|||||||
at Module._compile (module.js:*:*)
|
at Module._compile (module.js:*:*)
|
||||||
at evalScript (bootstrap_node.js:*:*)
|
at evalScript (bootstrap_node.js:*:*)
|
||||||
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
||||||
at emitNone (events.js:*:*)
|
|
||||||
at Socket.emit (events.js:*:*)
|
at Socket.emit (events.js:*:*)
|
||||||
at endReadableNT (_stream_readable.js:*:*)
|
at endReadableNT (_stream_readable.js:*:*)
|
||||||
at _combinedTickCallback (internal/process/next_tick.js:*:*)
|
at _combinedTickCallback (internal/process/next_tick.js:*:*)
|
||||||
|
at process._tickCallback (internal/process/next_tick.js:*:*)
|
||||||
42
|
42
|
||||||
42
|
42
|
||||||
[stdin]:1
|
[stdin]:1
|
||||||
@ -27,9 +27,9 @@ Error: hello
|
|||||||
at Module._compile (module.js:*:*)
|
at Module._compile (module.js:*:*)
|
||||||
at evalScript (bootstrap_node.js:*:*)
|
at evalScript (bootstrap_node.js:*:*)
|
||||||
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
||||||
at emitNone (events.js:*:*)
|
|
||||||
at Socket.emit (events.js:*:*)
|
at Socket.emit (events.js:*:*)
|
||||||
at endReadableNT (_stream_readable.js:*:*)
|
at endReadableNT (_stream_readable.js:*:*)
|
||||||
|
at _combinedTickCallback (internal/process/next_tick.js:*:*)
|
||||||
[stdin]:1
|
[stdin]:1
|
||||||
throw new Error("hello")
|
throw new Error("hello")
|
||||||
^
|
^
|
||||||
@ -42,9 +42,9 @@ Error: hello
|
|||||||
at Module._compile (module.js:*:*)
|
at Module._compile (module.js:*:*)
|
||||||
at evalScript (bootstrap_node.js:*:*)
|
at evalScript (bootstrap_node.js:*:*)
|
||||||
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
||||||
at emitNone (events.js:*:*)
|
|
||||||
at Socket.emit (events.js:*:*)
|
at Socket.emit (events.js:*:*)
|
||||||
at endReadableNT (_stream_readable.js:*:*)
|
at endReadableNT (_stream_readable.js:*:*)
|
||||||
|
at _combinedTickCallback (internal/process/next_tick.js:*:*)
|
||||||
100
|
100
|
||||||
[stdin]:1
|
[stdin]:1
|
||||||
var x = 100; y = x;
|
var x = 100; y = x;
|
||||||
@ -58,9 +58,9 @@ ReferenceError: y is not defined
|
|||||||
at Module._compile (module.js:*:*)
|
at Module._compile (module.js:*:*)
|
||||||
at evalScript (bootstrap_node.js:*:*)
|
at evalScript (bootstrap_node.js:*:*)
|
||||||
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
||||||
at emitNone (events.js:*:*)
|
|
||||||
at Socket.emit (events.js:*:*)
|
at Socket.emit (events.js:*:*)
|
||||||
at endReadableNT (_stream_readable.js:*:*)
|
at endReadableNT (_stream_readable.js:*:*)
|
||||||
|
at _combinedTickCallback (internal/process/next_tick.js:*:*)
|
||||||
|
|
||||||
[stdin]:1
|
[stdin]:1
|
||||||
var ______________________________________________; throw 10
|
var ______________________________________________; throw 10
|
||||||
|
Loading…
x
Reference in New Issue
Block a user