Permalink
Browse files

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 <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...
1 parent 00f791a commit 7ece950ffedd09a698fc4e81c49da024375aa50e @mscdex mscdex committed with evanlucas Dec 25, 2016
Showing with 33 additions and 10 deletions.
  1. +20 −0 benchmark/events/ee-once.js
  2. +13 −10 lib/events.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);
+}
View
@@ -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) {

0 comments on commit 7ece950

Please sign in to comment.