events: add check for listeners length

Ability to return just the length of listeners for a given type, using
EventEmitter.listenerCount(emitter, event). This will be a lot cheaper
than creating a copy of the listeners array just to check its length.
This commit is contained in:
Trevor Norris 2013-02-14 00:48:11 -08:00 committed by isaacs
parent 7707acd6ef
commit 75305f3bab
7 changed files with 32 additions and 14 deletions

View File

@ -87,6 +87,12 @@ Returns an array of listeners for the specified event.
Execute each of the listeners in order with the supplied arguments. Execute each of the listeners in order with the supplied arguments.
### Class Method: EventEmitter.listenerCount(emitter, event)
Return the number of listeners for a given event.
### Event: 'newListener' ### Event: 'newListener'
* `event` {String} The event name * `event` {String} The event name

View File

@ -22,6 +22,7 @@
module.exports = Readable; module.exports = Readable;
Readable.ReadableState = ReadableState; Readable.ReadableState = ReadableState;
var EE = require('events').EventEmitter;
var Stream = require('stream'); var Stream = require('stream');
var util = require('util'); var util = require('util');
var StringDecoder; var StringDecoder;
@ -451,7 +452,7 @@ Readable.prototype.pipe = function(dest, pipeOpts) {
// however, don't suppress the throwing behavior for this. // however, don't suppress the throwing behavior for this.
function onerror(er) { function onerror(er) {
unpipe(); unpipe();
if (dest.listeners('error').length === 0) if (EE.listenerCount(dest, 'error') === 0)
dest.emit('error', er); dest.emit('error', er);
} }
dest.once('error', onerror); dest.once('error', onerror);
@ -537,7 +538,7 @@ function flow(src) {
state.flowing = false; state.flowing = false;
// if there were data event listeners added, then switch to old mode. // if there were data event listeners added, then switch to old mode.
if (src.listeners('data').length) if (EE.listenerCount(src, 'data') > 0)
emitDataEvents(src); emitDataEvents(src);
return; return;
} }

View File

@ -286,3 +286,14 @@ EventEmitter.prototype.listeners = function(type) {
} }
return this._events[type].slice(0); return this._events[type].slice(0);
}; };
EventEmitter.listenerCount = function(emitter, type) {
var ret;
if (!emitter._events || !emitter._events[type])
ret = 0;
else if (typeof emitter._events[type] === 'function')
ret = 1;
else
ret = emitter._events[type].length;
return ret;
};

View File

@ -1161,7 +1161,7 @@ fs.unwatchFile = function(filename, listener) {
stat.removeAllListeners('change'); stat.removeAllListeners('change');
} }
if (stat.listeners('change').length === 0) { if (EventEmitter.listenerCount(stat, 'change') === 0) {
stat.stop(); stat.stop();
statWatchers[filename] = undefined; statWatchers[filename] = undefined;
} }

View File

@ -1523,7 +1523,7 @@ function socketOnData(d, start, end) {
var bodyHead = d.slice(start + bytesParsed, end); var bodyHead = d.slice(start + bytesParsed, end);
var eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade'; var eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade';
if (req.listeners(eventName).length) { if (EventEmitter.listenerCount(req, eventName) > 0) {
req.upgradeOrConnect = true; req.upgradeOrConnect = true;
// detach the socket // detach the socket
@ -1874,7 +1874,7 @@ function connectionListener(socket) {
var bodyHead = d.slice(start + bytesParsed, end); var bodyHead = d.slice(start + bytesParsed, end);
var eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade'; var eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade';
if (self.listeners(eventName).length) { if (EventEmitter.listenerCount(self, eventName) > 0) {
self.emit(eventName, req, req.socket, bodyHead); self.emit(eventName, req, req.socket, bodyHead);
} else { } else {
// Got upgrade header or CONNECT method, but have no handler. // Got upgrade header or CONNECT method, but have no handler.
@ -1958,7 +1958,7 @@ function connectionListener(socket) {
(req.httpVersionMajor == 1 && req.httpVersionMinor == 1) && (req.httpVersionMajor == 1 && req.httpVersionMinor == 1) &&
continueExpression.test(req.headers['expect'])) { continueExpression.test(req.headers['expect'])) {
res._expect_continue = true; res._expect_continue = true;
if (self.listeners('checkContinue').length) { if (EventEmitter.listenerCount(self, 'checkContinue') > 0) {
self.emit('checkContinue', req, res); self.emit('checkContinue', req, res);
} else { } else {
res.writeContinue(); res.writeContinue();

View File

@ -616,7 +616,7 @@ Interface.prototype._ttyWrite = function(s, key) {
switch (key.name) { switch (key.name) {
case 'c': case 'c':
if (this.listeners('SIGINT').length) { if (EventEmitter.listenerCount(this, 'SIGINT') > 0) {
this.emit('SIGINT'); this.emit('SIGINT');
} else { } else {
// This readline instance is finished // This readline instance is finished
@ -673,7 +673,7 @@ Interface.prototype._ttyWrite = function(s, key) {
case 'z': case 'z':
if (process.platform == 'win32') break; if (process.platform == 'win32') break;
if (this.listeners('SIGTSTP').length) { if (EventEmitter.listenerCount(this, 'SIGTSTP') > 0) {
this.emit('SIGTSTP'); this.emit('SIGTSTP');
} else { } else {
process.once('SIGCONT', (function(self) { process.once('SIGCONT', (function(self) {
@ -829,7 +829,7 @@ function emitKeypressEvents(stream) {
stream._keypressDecoder = new StringDecoder('utf8'); stream._keypressDecoder = new StringDecoder('utf8');
function onData(b) { function onData(b) {
if (stream.listeners('keypress').length > 0) { if (EventEmitter.listenerCount(stream, 'keypress') > 0) {
var r = stream._keypressDecoder.write(b); var r = stream._keypressDecoder.write(b);
if (r) emitKey(stream, r); if (r) emitKey(stream, r);
} else { } else {
@ -846,7 +846,7 @@ function emitKeypressEvents(stream) {
} }
} }
if (stream.listeners('keypress').length > 0) { if (EventEmitter.listenerCount(stream, 'keypress') > 0) {
stream.on('data', onData); stream.on('data', onData);
} else { } else {
stream.on('newListener', onNewListener); stream.on('newListener', onNewListener);

View File

@ -21,10 +21,10 @@
module.exports = Stream; module.exports = Stream;
var events = require('events'); var EE = require('events').EventEmitter;
var util = require('util'); var util = require('util');
util.inherits(Stream, events.EventEmitter); util.inherits(Stream, EE);
Stream.Readable = require('_stream_readable'); Stream.Readable = require('_stream_readable');
Stream.Writable = require('_stream_writable'); Stream.Writable = require('_stream_writable');
Stream.Duplex = require('_stream_duplex'); Stream.Duplex = require('_stream_duplex');
@ -40,7 +40,7 @@ Stream.Stream = Stream;
// part of this class) is overridden in the Readable class. // part of this class) is overridden in the Readable class.
function Stream() { function Stream() {
events.EventEmitter.call(this); EE.call(this);
} }
Stream.prototype.pipe = function(dest, options) { Stream.prototype.pipe = function(dest, options) {
@ -90,7 +90,7 @@ Stream.prototype.pipe = function(dest, options) {
// don't leave dangling pipes when there are errors. // don't leave dangling pipes when there are errors.
function onerror(er) { function onerror(er) {
cleanup(); cleanup();
if (this.listeners('error').length === 0) { if (EE.listenerCount(this, 'error') === 0) {
throw er; // Unhandled stream error in pipe. throw er; // Unhandled stream error in pipe.
} }
} }