From b1d580c9d2208aeda6dcb2e1bd91069247924bcd Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Fri, 12 Feb 2016 15:18:21 +0530 Subject: [PATCH] doc: update removeListener behaviour This commit updates events doc to describe removeListener behaviour when it is called within a listener. An example is added to make it more evident. A test is also incuded to make this behaviour consistent in future releases. Fixes: nodejs/node#4759 PR-URL: https://github.com/nodejs/node/pull/5201 Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Benjamin Gruenbaum --- doc/api/events.markdown | 37 +++++++++++++++++++ .../test-event-emitter-remove-listeners.js | 19 ++++++++++ 2 files changed, 56 insertions(+) diff --git a/doc/api/events.markdown b/doc/api/events.markdown index 0afd583ebc35d7..797b969ecc2824 100644 --- a/doc/api/events.markdown +++ b/doc/api/events.markdown @@ -377,6 +377,43 @@ listener array. If any single listener has been added multiple times to the listener array for the specified `event`, then `removeListener` must be called multiple times to remove each instance. +Note that once an event has been emitted, all listeners attached to it at the +time of emitting will be called in order. This implies that any `removeListener()` +or `removeAllListeners()` calls *after* emitting and *before* the last listener +finishes execution will not remove them from `emit()` in progress. Subsequent +events will behave as expected. + +```js +const myEmitter = new MyEmitter(); + +var callbackA = () => { + console.log('A'); + myEmitter.removeListener('event', callbackB); +}; + +var callbackB = () => { + console.log('B'); +}; + +myEmitter.on('event', callbackA); + +myEmitter.on('event', callbackB); + +// callbackA removes listener callbackB but it will still be called. +// Interal listener array at time of emit [callbackA, callbackB] +myEmitter.emit('event'); + // Prints: + // A + // B + +// callbackB is now removed. +// Interal listener array [callbackA] +myEmitter.emit('event'); + // Prints: + // A + +``` + Because listeners are managed using an internal array, calling this will change the position indices of any listener registered *after* the listener being removed. This will not impact the order in which listeners are called, diff --git a/test/parallel/test-event-emitter-remove-listeners.js b/test/parallel/test-event-emitter-remove-listeners.js index 396979a923d1ac..cc6f9516b5e3f3 100644 --- a/test/parallel/test-event-emitter-remove-listeners.js +++ b/test/parallel/test-event-emitter-remove-listeners.js @@ -83,3 +83,22 @@ e5.once('removeListener', common.mustCall(function(name, cb) { })); e5.removeListener('hello', listener1); assert.deepEqual([], e5.listeners('hello')); + +const e6 = new events.EventEmitter(); + +const listener3 = common.mustCall(() => { + e6.removeListener('hello', listener4); +}, 2); + +const listener4 = common.mustCall(() => {}, 1); + +e6.on('hello', listener3); +e6.on('hello', listener4); + +// listener4 will still be called although it is removed by listener 3. +e6.emit('hello'); +// This is so because the interal listener array at time of emit +// was [listener3,listener4] + +// Interal listener array [listener3] +e6.emit('hello');