Browse Source

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: https://github.com/nodejs/node/pull/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>
v6
Brian White 8 years ago
parent
commit
4c9dd6822e
No known key found for this signature in database GPG Key ID: 606D7358F94DA209
  1. 20
      benchmark/events/ee-once.js
  2. 21
      lib/events.js

20
benchmark/events/ee-once.js

@ -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);
}

21
lib/events.js

@ -283,17 +283,20 @@ EventEmitter.prototype.prependListener =
return _addListener(this, type, listener, true); return _addListener(this, type, listener, true);
}; };
function _onceWrap(target, type, listener) { function onceWrapper() {
var fired = false; this.target.removeListener(this.type, this.wrapFn);
function g() { if (!this.fired) {
target.removeListener(type, g); this.fired = true;
if (!fired) { this.listener.apply(this.target, arguments);
fired = true;
listener.apply(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) { EventEmitter.prototype.once = function once(type, listener) {

Loading…
Cancel
Save