Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
events: improve once() performance
This commit takes advantage of the performance improvements V8 has
made to function.bind() in V8 5.4 and uses it to avoid constant
recompilation/reoptimization of the wrapper closure used in once().
This change results in ~27% performance increase for once().

PR-URL: #10445
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Teddy Katz <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
  • Loading branch information
mscdex committed Dec 29, 2016
commit 4c9dd6822eb9520588e4d06d251ce8e32469d4bc
20 changes: 20 additions & 0 deletions benchmark/events/ee-once.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';
var common = require('../common.js');
var EventEmitter = require('events').EventEmitter;

var bench = common.createBenchmark(main, {n: [2e7]});

function main(conf) {
var n = conf.n | 0;

var ee = new EventEmitter();

function listener() {}

bench.start();
for (var i = 0; i < n; i += 1) {
ee.once('dummy', listener);
ee.emit('dummy');
}
bench.end(n);
}
23 changes: 13 additions & 10 deletions lib/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -283,17 +283,20 @@ EventEmitter.prototype.prependListener =
return _addListener(this, type, listener, true);
};

function _onceWrap(target, type, listener) {
var fired = false;
function g() {
target.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(target, arguments);
}
function onceWrapper() {
this.target.removeListener(this.type, this.wrapFn);
if (!this.fired) {
this.fired = true;
this.listener.apply(this.target, arguments);
}
g.listener = listener;
return g;
}

function _onceWrap(target, type, listener) {
var state = { fired: false, wrapFn: undefined, target, type, listener };
var wrapped = onceWrapper.bind(state);
wrapped.listener = listener;
state.wrapFn = wrapped;
return wrapped;
}

EventEmitter.prototype.once = function once(type, listener) {
Expand Down