Skip to content

Commit

Permalink
events: improve arrayClone performance
Browse files Browse the repository at this point in the history
PR-URL: #33774
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Zeyu Yang <himself65@outlook.com>
  • Loading branch information
mscdex authored and addaleax committed Sep 21, 2020
1 parent 1a09b4d commit 830574f
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 37 deletions.
1 change: 1 addition & 0 deletions benchmark/events/ee-emit.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const bench = common.createBenchmark(main, {

function main({ n, argc, listeners }) {
const ee = new EventEmitter();
ee.setMaxListeners(listeners + 1);

for (let k = 0; k < listeners; k += 1)
ee.on('dummy', () => {});
Expand Down
22 changes: 0 additions & 22 deletions benchmark/events/ee-listeners-many.js

This file was deleted.

30 changes: 22 additions & 8 deletions benchmark/events/ee-listeners.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,34 @@
const common = require('../common.js');
const EventEmitter = require('events').EventEmitter;

const bench = common.createBenchmark(main, { n: [5e6] });
const bench = common.createBenchmark(main, {
n: [5e6],
listeners: [5, 50],
raw: ['true', 'false']
});

function main({ n }) {
function main({ n, listeners, raw }) {
const ee = new EventEmitter();
ee.setMaxListeners(listeners * 2 + 1);

for (let k = 0; k < 5; k += 1) {
for (let k = 0; k < listeners; k += 1) {
ee.on('dummy0', () => {});
ee.on('dummy1', () => {});
}

bench.start();
for (let i = 0; i < n; i += 1) {
const dummy = (i % 2 === 0) ? 'dummy0' : 'dummy1';
ee.listeners(dummy);
if (raw === 'true') {
bench.start();
for (let i = 0; i < n; i += 1) {
const dummy = (i % 2 === 0) ? 'dummy0' : 'dummy1';
ee.rawListeners(dummy);
}
bench.end(n);
} else {
bench.start();
for (let i = 0; i < n; i += 1) {
const dummy = (i % 2 === 0) ? 'dummy0' : 'dummy1';
ee.listeners(dummy);
}
bench.end(n);
}
bench.end(n);
}
20 changes: 13 additions & 7 deletions lib/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ EventEmitter.prototype.emit = function emit(type, ...args) {
}
} else {
const len = handler.length;
const listeners = arrayClone(handler, len);
const listeners = arrayClone(handler);
for (let i = 0; i < len; ++i) {
const result = ReflectApply(listeners[i], this, args);

Expand Down Expand Up @@ -563,7 +563,7 @@ function _listeners(target, type, unwrap) {
return unwrap ? [evlistener.listener || evlistener] : [evlistener];

return unwrap ?
unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
unwrapListeners(evlistener) : arrayClone(evlistener);
}

EventEmitter.prototype.listeners = function listeners(type) {
Expand Down Expand Up @@ -602,11 +602,17 @@ EventEmitter.prototype.eventNames = function eventNames() {
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
};

function arrayClone(arr, n) {
const copy = new Array(n);
for (let i = 0; i < n; ++i)
copy[i] = arr[i];
return copy;
function arrayClone(arr) {
// At least since V8 8.3, this implementation is faster than the previous
// which always used a simple for-loop
switch (arr.length) {
case 2: return [arr[0], arr[1]];
case 3: return [arr[0], arr[1], arr[2]];
case 4: return [arr[0], arr[1], arr[2], arr[3]];
case 5: return [arr[0], arr[1], arr[2], arr[3], arr[4]];
case 6: return [arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]];
}
return arr.slice();
}

function unwrapListeners(arr) {
Expand Down

0 comments on commit 830574f

Please sign in to comment.