From 75305f3babd9e927e92b0d9b70d8bb026492ebd0 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Thu, 14 Feb 2013 00:48:11 -0800 Subject: [PATCH] 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. --- doc/api/events.markdown | 6 ++++++ lib/_stream_readable.js | 5 +++-- lib/events.js | 11 +++++++++++ lib/fs.js | 2 +- lib/http.js | 6 +++--- lib/readline.js | 8 ++++---- lib/stream.js | 8 ++++---- 7 files changed, 32 insertions(+), 14 deletions(-) diff --git a/doc/api/events.markdown b/doc/api/events.markdown index 7998684e739b51..10b9ed0441f5cd 100644 --- a/doc/api/events.markdown +++ b/doc/api/events.markdown @@ -87,6 +87,12 @@ Returns an array of listeners for the specified event. 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` {String} The event name diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index b9f8291874f1c6..d22795a4041461 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -22,6 +22,7 @@ module.exports = Readable; Readable.ReadableState = ReadableState; +var EE = require('events').EventEmitter; var Stream = require('stream'); var util = require('util'); var StringDecoder; @@ -451,7 +452,7 @@ Readable.prototype.pipe = function(dest, pipeOpts) { // however, don't suppress the throwing behavior for this. function onerror(er) { unpipe(); - if (dest.listeners('error').length === 0) + if (EE.listenerCount(dest, 'error') === 0) dest.emit('error', er); } dest.once('error', onerror); @@ -537,7 +538,7 @@ function flow(src) { state.flowing = false; // 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); return; } diff --git a/lib/events.js b/lib/events.js index 223015ec6024dd..69af3aee600fc1 100644 --- a/lib/events.js +++ b/lib/events.js @@ -286,3 +286,14 @@ EventEmitter.prototype.listeners = function(type) { } 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; +}; diff --git a/lib/fs.js b/lib/fs.js index 1ad0b2e3ce9f57..d467c5e0cc147c 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1161,7 +1161,7 @@ fs.unwatchFile = function(filename, listener) { stat.removeAllListeners('change'); } - if (stat.listeners('change').length === 0) { + if (EventEmitter.listenerCount(stat, 'change') === 0) { stat.stop(); statWatchers[filename] = undefined; } diff --git a/lib/http.js b/lib/http.js index 56d9aae4236361..638cb0cb4bb884 100644 --- a/lib/http.js +++ b/lib/http.js @@ -1523,7 +1523,7 @@ function socketOnData(d, start, end) { var bodyHead = d.slice(start + bytesParsed, end); var eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade'; - if (req.listeners(eventName).length) { + if (EventEmitter.listenerCount(req, eventName) > 0) { req.upgradeOrConnect = true; // detach the socket @@ -1874,7 +1874,7 @@ function connectionListener(socket) { var bodyHead = d.slice(start + bytesParsed, end); 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); } else { // Got upgrade header or CONNECT method, but have no handler. @@ -1958,7 +1958,7 @@ function connectionListener(socket) { (req.httpVersionMajor == 1 && req.httpVersionMinor == 1) && continueExpression.test(req.headers['expect'])) { res._expect_continue = true; - if (self.listeners('checkContinue').length) { + if (EventEmitter.listenerCount(self, 'checkContinue') > 0) { self.emit('checkContinue', req, res); } else { res.writeContinue(); diff --git a/lib/readline.js b/lib/readline.js index a2d7e1c82256f6..83b425c4df202a 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -616,7 +616,7 @@ Interface.prototype._ttyWrite = function(s, key) { switch (key.name) { case 'c': - if (this.listeners('SIGINT').length) { + if (EventEmitter.listenerCount(this, 'SIGINT') > 0) { this.emit('SIGINT'); } else { // This readline instance is finished @@ -673,7 +673,7 @@ Interface.prototype._ttyWrite = function(s, key) { case 'z': if (process.platform == 'win32') break; - if (this.listeners('SIGTSTP').length) { + if (EventEmitter.listenerCount(this, 'SIGTSTP') > 0) { this.emit('SIGTSTP'); } else { process.once('SIGCONT', (function(self) { @@ -829,7 +829,7 @@ function emitKeypressEvents(stream) { stream._keypressDecoder = new StringDecoder('utf8'); function onData(b) { - if (stream.listeners('keypress').length > 0) { + if (EventEmitter.listenerCount(stream, 'keypress') > 0) { var r = stream._keypressDecoder.write(b); if (r) emitKey(stream, r); } else { @@ -846,7 +846,7 @@ function emitKeypressEvents(stream) { } } - if (stream.listeners('keypress').length > 0) { + if (EventEmitter.listenerCount(stream, 'keypress') > 0) { stream.on('data', onData); } else { stream.on('newListener', onNewListener); diff --git a/lib/stream.js b/lib/stream.js index 481d7644e5e832..098ff613d27861 100644 --- a/lib/stream.js +++ b/lib/stream.js @@ -21,10 +21,10 @@ module.exports = Stream; -var events = require('events'); +var EE = require('events').EventEmitter; var util = require('util'); -util.inherits(Stream, events.EventEmitter); +util.inherits(Stream, EE); Stream.Readable = require('_stream_readable'); Stream.Writable = require('_stream_writable'); Stream.Duplex = require('_stream_duplex'); @@ -40,7 +40,7 @@ Stream.Stream = Stream; // part of this class) is overridden in the Readable class. function Stream() { - events.EventEmitter.call(this); + EE.call(this); } 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. function onerror(er) { cleanup(); - if (this.listeners('error').length === 0) { + if (EE.listenerCount(this, 'error') === 0) { throw er; // Unhandled stream error in pipe. } }