lib: micro-optimize EventEmitter#removeListener()
authorBen Noordhuis <info@bnoordhuis.nl>
Fri, 19 Dec 2014 23:04:35 +0000 (00:04 +0100)
committerBen Noordhuis <info@bnoordhuis.nl>
Sat, 20 Dec 2014 01:39:42 +0000 (02:39 +0100)
Replace the call to Array#splice() with a faster open-coded version
that creates less garbage.

Add a new benchmark to prove it.  With the change applied, it scores
a whopping 40% higher.

PR-URL: https://github.com/iojs/io.js/pull/185
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
benchmark/events/ee-add-remove.js [new file with mode: 0644]
lib/events.js

diff --git a/benchmark/events/ee-add-remove.js b/benchmark/events/ee-add-remove.js
new file mode 100644 (file)
index 0000000..cd9fe3c
--- /dev/null
@@ -0,0 +1,23 @@
+var common = require('../common.js');
+var events = require('events');
+
+var bench = common.createBenchmark(main, {n: [25e4]});
+
+function main(conf) {
+  var n = conf.n | 0;
+
+  var ee = new events.EventEmitter();
+  var listeners = [];
+
+  for (var k = 0; k < 10; k += 1)
+    listeners.push(function() {});
+
+  bench.start();
+  for (var i = 0; i < n; i += 1) {
+    for (var k = listeners.length; --k >= 0; /* empty */)
+      ee.on('dummy', listeners[k]);
+    for (var k = listeners.length; --k >= 0; /* empty */)
+      ee.removeListener('dummy', listeners[k]);
+  }
+  bench.end(n);
+}
index 3ee1679..49b49e6 100644 (file)
@@ -246,7 +246,7 @@ EventEmitter.prototype.removeListener =
       list.length = 0;
       delete this._events[type];
     } else {
-      list.splice(position, 1);
+      spliceOne(list, position);
     }
 
     if (this._events.removeListener)
@@ -318,3 +318,10 @@ EventEmitter.listenerCount = function(emitter, type) {
     ret = emitter._events[type].length;
   return ret;
 };
+
+// About 1.5x faster than the two-arg version of Array#splice().
+function spliceOne(list, index) {
+  for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)
+    list[i] = list[k];
+  list.pop();
+}