Print error when EventEmitters get too many listeners
authorRyan Dahl <ry@tinyclouds.org>
Sat, 1 Jan 2011 02:32:52 +0000 (18:32 -0800)
committerRyan Dahl <ry@tinyclouds.org>
Mon, 10 Jan 2011 21:48:35 +0000 (13:48 -0800)
doc/api/events.markdown
lib/events.js

index e069559..5749b58 100644 (file)
@@ -61,6 +61,14 @@ Remove a listener from the listener array for the specified event.
 Removes all listeners from the listener array for the specified event.
 
 
+#### emitter.setMaxListeners(n)
+
+By default EventEmitters will print a warning if more than 10 listeners are
+added to it. This is a useful default which helps finding memory leaks.
+Obviously not all Emitters should be limited to 10. This function allows
+that to be increased. Set to zero for unlimited.
+
+
 #### emitter.listeners(event)
 
 Returns an array of listeners for the specified event. This array can be
index ad3ce72..6505606 100644 (file)
@@ -1,7 +1,18 @@
 var EventEmitter = exports.EventEmitter = process.EventEmitter;
-
 var isArray = Array.isArray;
 
+// By default EventEmitters will print a warning if more than
+// 10 listeners are added to it. This is a useful default which
+// helps finding memory leaks.
+//
+// Obviously not all Emitters should be limited to 10. This function allows
+// that to be increased. Set to zero for unlimited.
+var defaultMaxListeners = 10;
+EventEmitter.prototype.setMaxListeners = function(n) {
+  this._events.maxListeners = n;
+};
+
+
 EventEmitter.prototype.emit = function(type) {
   // If there is no 'error' event listener then throw.
   if (type === 'error') {
@@ -71,6 +82,26 @@ EventEmitter.prototype.addListener = function(type, listener) {
     // Optimize the case of one listener. Don't need the extra array object.
     this._events[type] = listener;
   } else if (isArray(this._events[type])) {
+
+    // Check for listener leak
+    if (!this._events[type].warned) {
+      var m;
+      if (this._events.maxListeners !== undefined) {
+        m = this._events.maxListeners;
+      } else {
+        m = defaultMaxListeners;
+      }
+
+      if (m && m > 0 && this._events[type].length > m) {
+        this._events[type].warned = true;
+        console.error('(node) warning: possible EventEmitter memory ' +
+                      'leak detected. %d listeners added. ' +
+                      'Use emitter.setMaxListeners() to increase limit.',
+                      this._events[type].length);
+        console.trace();
+      }
+    }
+
     // If we've already got an array, just append.
     this._events[type].push(listener);
   } else {