Permalink
Browse files

events: add 'removeListener' event

  • Loading branch information...
1 parent d0e6c3f commit 84221fd1d690070877adacd365ac6429b92bd838 @bnoordhuis bnoordhuis committed Jul 31, 2012
View
@@ -26,7 +26,7 @@ If there is no listener for it, then the default action is to print a stack
trace and exit the program.
All EventEmitters emit the event `'newListener'` when new listeners are
-added.
+added and `'removeListener'` when a listener is removed.
### emitter.addListener(event, listener)
### emitter.on(event, listener)
View
@@ -191,6 +191,7 @@ EventEmitter.prototype.once = function(type, listener) {
return this;
};
+// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function(type, listener) {
if ('function' !== typeof listener) {
throw new Error('removeListener only takes instances of Function');
@@ -216,23 +217,41 @@ EventEmitter.prototype.removeListener = function(type, listener) {
list.splice(position, 1);
if (list.length == 0)
delete this._events[type];
+ this.emit('removeListener', type, listener);
} else if (list === listener ||
(list.listener && list.listener === listener))
{
delete this._events[type];
+ this.emit('removeListener', type, listener);
}
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
+ if (!this._events) return this;
+
if (arguments.length === 0) {
+ for (var key in this._events) {
+ if (key === 'removeListener') continue;
+ this.removeAllListeners(key);
+ }
+ this.removeAllListeners('removeListener');
this._events = {};
return this;
}
- // does not use listeners(), so no side effect of creating _events[type]
- if (type && this._events && this._events[type]) this._events[type] = null;
+ var listeners = this._events[type];
+ if (isArray(listeners)) {
+ while (listeners.length) {
+ // LIFO order
+ this.removeListener(type, listeners[listeners.length - 1]);
+ }
+ } else if (listeners) {
+ this.removeListener(type, listeners);
+ }
+ this._events[type] = null;
+
return this;
};
@@ -24,6 +24,17 @@ var assert = require('assert');
var events = require('events');
+function expect(expected) {
+ var actual = [];
+ process.on('exit', function() {
+ assert.deepEqual(actual.sort(), expected.sort());
+ });
+ function listener(name) {
+ actual.push(name)
+ }
+ return common.mustCall(listener, expected.length);
+}
+
function listener() {}
var e1 = new events.EventEmitter();
@@ -34,6 +45,7 @@ e1.on('baz', listener);
var fooListeners = e1.listeners('foo');
var barListeners = e1.listeners('bar');
var bazListeners = e1.listeners('baz');
+e1.on('removeListener', expect(['bar', 'baz', 'baz']));
e1.removeAllListeners('bar');
e1.removeAllListeners('baz');
assert.deepEqual(e1.listeners('foo'), [listener]);
@@ -52,6 +64,9 @@ assert.notEqual(e1.listeners('baz'), bazListeners);
var e2 = new events.EventEmitter();
e2.on('foo', listener);
e2.on('bar', listener);
+// expect LIFO order
+e2.on('removeListener', expect(['foo', 'bar', 'removeListener']));
+e2.on('removeListener', expect(['foo', 'bar']));
e2.removeAllListeners();
console.error(e2);
assert.deepEqual([], e2.listeners('foo'));
@@ -23,7 +23,6 @@ var common = require('../common');
var assert = require('assert');
var events = require('events');
-
var count = 0;
function listener1() {
@@ -41,21 +40,45 @@ function listener3() {
count++;
}
+function remove1() {
+ assert(0);
+}
+
+function remove2() {
+ assert(0);
+}
+
var e1 = new events.EventEmitter();
e1.on('hello', listener1);
+e1.on('removeListener', common.mustCall(function(name, cb) {
+ assert.equal(name, 'hello');
+ assert.equal(cb, listener1);
+}));
e1.removeListener('hello', listener1);
assert.deepEqual([], e1.listeners('hello'));
var e2 = new events.EventEmitter();
e2.on('hello', listener1);
+e2.on('removeListener', assert.fail);
e2.removeListener('hello', listener2);
assert.deepEqual([listener1], e2.listeners('hello'));
var e3 = new events.EventEmitter();
e3.on('hello', listener1);
e3.on('hello', listener2);
+e3.on('removeListener', common.mustCall(function(name, cb) {
+ assert.equal(name, 'hello');
+ assert.equal(cb, listener1);
+}));
e3.removeListener('hello', listener1);
assert.deepEqual([listener2], e3.listeners('hello'));
-
-
+var e4 = new events.EventEmitter();
+e4.on('removeListener', common.mustCall(function(name, cb) {
+ if (cb !== remove1) return;
+ this.removeListener('quux', remove2);
+ this.emit('quux');
+}, 2));
+e4.on('quux', remove1);
+e4.on('quux', remove2);
+e4.removeListener('quux', remove1);

0 comments on commit 84221fd

Please sign in to comment.