Skip to content

Commit

Permalink
events: improve once() performance
Browse files Browse the repository at this point in the history
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 <luigipinca@gmail.com>
Reviewed-By: Teddy Katz <teddy.katz@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
  • Loading branch information
mscdex authored and evanlucas committed Jan 4, 2017
1 parent 00f791a commit 7ece950
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 10 deletions.
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

0 comments on commit 7ece950

Please sign in to comment.