Skip to content

Commit 7ece950

Browse files
mscdexevanlucas
authored andcommitted
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]>
1 parent 00f791a commit 7ece950

File tree

2 files changed

+33
-10
lines changed

2 files changed

+33
-10
lines changed

benchmark/events/ee-once.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict';
2+
var common = require('../common.js');
3+
var EventEmitter = require('events').EventEmitter;
4+
5+
var bench = common.createBenchmark(main, {n: [2e7]});
6+
7+
function main(conf) {
8+
var n = conf.n | 0;
9+
10+
var ee = new EventEmitter();
11+
12+
function listener() {}
13+
14+
bench.start();
15+
for (var i = 0; i < n; i += 1) {
16+
ee.once('dummy', listener);
17+
ee.emit('dummy');
18+
}
19+
bench.end(n);
20+
}

lib/events.js

+13-10
Original file line numberDiff line numberDiff line change
@@ -283,17 +283,20 @@ EventEmitter.prototype.prependListener =
283283
return _addListener(this, type, listener, true);
284284
};
285285

286-
function _onceWrap(target, type, listener) {
287-
var fired = false;
288-
function g() {
289-
target.removeListener(type, g);
290-
if (!fired) {
291-
fired = true;
292-
listener.apply(target, arguments);
293-
}
286+
function onceWrapper() {
287+
this.target.removeListener(this.type, this.wrapFn);
288+
if (!this.fired) {
289+
this.fired = true;
290+
this.listener.apply(this.target, arguments);
294291
}
295-
g.listener = listener;
296-
return g;
292+
}
293+
294+
function _onceWrap(target, type, listener) {
295+
var state = { fired: false, wrapFn: undefined, target, type, listener };
296+
var wrapped = onceWrapper.bind(state);
297+
wrapped.listener = listener;
298+
state.wrapFn = wrapped;
299+
return wrapped;
297300
}
298301

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

0 commit comments

Comments
 (0)