Skip to content

Commit

Permalink
events: optimize eventEmitter.once()
Browse files Browse the repository at this point in the history
This basically removes the extra closure previously created by
once() and instead uses an object to denote a one-time handler.
The result is ~340% performance increase when adding one-time
handlers, ~48% performance increase when emitting events with
mixed persistent and one-time handlers, and ~10% performance
increase when emitting with multiple arguments with mixed handlers,
all with negligible negative performance impact to other EventEmitter
functionality.

Also, removeListener() was optimized a bit by eliminating handler
arrays of length 1 so that the leftover handler is set on
_events[type].
  • Loading branch information
mscdex committed Feb 21, 2015
1 parent d8eb974 commit 92806a3
Show file tree
Hide file tree
Showing 4 changed files with 346 additions and 111 deletions.
28 changes: 20 additions & 8 deletions lib/_stream_readable.js
Original file line number Diff line number Diff line change
Expand Up @@ -543,10 +543,16 @@ Readable.prototype.pipe = function(dest, pipeOpts) {
// is attached before any userland ones. NEVER DO THIS.
if (!dest._events || !dest._events.error)
dest.on('error', onerror);
else if (Array.isArray(dest._events.error))
dest._events.error.unshift(onerror);
else
dest._events.error = [onerror, dest._events.error];
else {
var existingHandler = dest._events.error;
if (Array.isArray(existingHandler))
existingHandler.unshift(onerror);
else {
var handlers = [onerror, existingHandler];
handlers.onceCount = (existingHandler.once ? 1 : 0);
dest._events.error = handlers;
}
}



Expand Down Expand Up @@ -651,9 +657,7 @@ Readable.prototype.unpipe = function(dest) {

// set up data events if they are asked for
// Ensure readable listeners eventually get something
Readable.prototype.on = function(ev, fn) {
var res = Stream.prototype.on.call(this, ev, fn);

Readable.prototype._on = function(ev) {
// If listening to data, and it has not explicitly been paused,
// then call resume to start the flow of data on the next tick.
if (ev === 'data' && false !== this._readableState.flowing) {
Expand All @@ -677,7 +681,15 @@ Readable.prototype.on = function(ev, fn) {
}
}
}

};
Readable.prototype.on = function(ev, fn) {
var res = Stream.prototype.on.call(this, ev, fn);
this._on(ev);
return res;
};
Readable.prototype.once = function(ev, fn) {
var res = Stream.prototype.once.call(this, ev, fn);
this._on(ev);
return res;
};
Readable.prototype.addListener = Readable.prototype.on;
Expand Down
Loading

0 comments on commit 92806a3

Please sign in to comment.