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:
Родитель
6b351e92dc
Коммит
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 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) {
|
||||
const n = conf.n | 0;
|
||||
const argc = conf.argc | 0;
|
||||
const listeners = Math.max(conf.listeners | 0, 1);
|
||||
|
||||
const ee = new EventEmitter();
|
||||
|
||||
for (var k = 0; k < 10; k += 1)
|
||||
for (var k = 0; k < listeners; k += 1)
|
||||
ee.on('dummy', function() {});
|
||||
|
||||
bench.start();
|
||||
for (var i = 0; i < n; i += 1) {
|
||||
ee.emit('dummy');
|
||||
var i;
|
||||
switch (argc) {
|
||||
case 2:
|
||||
bench.start();
|
||||
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');
|
||||
}
|
||||
bench.end(n);
|
||||
break;
|
||||
}
|
||||
bench.end(n);
|
||||
}
|
||||
|
|
|
@ -105,63 +105,6 @@ EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
|
|||
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) {
|
||||
let doError = (type === 'error');
|
||||
|
||||
|
@ -212,22 +155,13 @@ EventEmitter.prototype.emit = function emit(type, ...args) {
|
|||
needDomainExit = true;
|
||||
}
|
||||
|
||||
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:
|
||||
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 (typeof handler === 'function') {
|
||||
handler.apply(this, args);
|
||||
} else {
|
||||
const len = handler.length;
|
||||
const listeners = arrayClone(handler, len);
|
||||
for (var i = 0; i < len; ++i)
|
||||
listeners[i].apply(this, args);
|
||||
}
|
||||
|
||||
if (needDomainExit)
|
||||
|
@ -313,23 +247,11 @@ EventEmitter.prototype.prependListener =
|
|||
return _addListener(this, type, listener, true);
|
||||
};
|
||||
|
||||
function onceWrapper() {
|
||||
function onceWrapper(...args) {
|
||||
if (!this.fired) {
|
||||
this.target.removeListener(this.type, this.wrapFn);
|
||||
this.fired = true;
|
||||
switch (arguments.length) {
|
||||
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);
|
||||
}
|
||||
this.listener.apply(this.target, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,10 +9,10 @@ SyntaxError: Strict mode code may not include a with statement
|
|||
at Module._compile (module.js:*:*)
|
||||
at evalScript (bootstrap_node.js:*:*)
|
||||
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
||||
at emitNone (events.js:*:*)
|
||||
at Socket.emit (events.js:*:*)
|
||||
at endReadableNT (_stream_readable.js:*:*)
|
||||
at _combinedTickCallback (internal/process/next_tick.js:*:*)
|
||||
at process._tickCallback (internal/process/next_tick.js:*:*)
|
||||
42
|
||||
42
|
||||
[stdin]:1
|
||||
|
@ -27,9 +27,9 @@ Error: hello
|
|||
at Module._compile (module.js:*:*)
|
||||
at evalScript (bootstrap_node.js:*:*)
|
||||
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
||||
at emitNone (events.js:*:*)
|
||||
at Socket.emit (events.js:*:*)
|
||||
at endReadableNT (_stream_readable.js:*:*)
|
||||
at _combinedTickCallback (internal/process/next_tick.js:*:*)
|
||||
[stdin]:1
|
||||
throw new Error("hello")
|
||||
^
|
||||
|
@ -42,9 +42,9 @@ Error: hello
|
|||
at Module._compile (module.js:*:*)
|
||||
at evalScript (bootstrap_node.js:*:*)
|
||||
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
||||
at emitNone (events.js:*:*)
|
||||
at Socket.emit (events.js:*:*)
|
||||
at endReadableNT (_stream_readable.js:*:*)
|
||||
at _combinedTickCallback (internal/process/next_tick.js:*:*)
|
||||
100
|
||||
[stdin]:1
|
||||
var x = 100; y = x;
|
||||
|
@ -58,9 +58,9 @@ ReferenceError: y is not defined
|
|||
at Module._compile (module.js:*:*)
|
||||
at evalScript (bootstrap_node.js:*:*)
|
||||
at Socket.<anonymous> (bootstrap_node.js:*:*)
|
||||
at emitNone (events.js:*:*)
|
||||
at Socket.emit (events.js:*:*)
|
||||
at endReadableNT (_stream_readable.js:*:*)
|
||||
at _combinedTickCallback (internal/process/next_tick.js:*:*)
|
||||
|
||||
[stdin]:1
|
||||
var ______________________________________________; throw 10
|
||||
|
|
Загрузка…
Ссылка в новой задаче