diff --git a/doc/api/events.markdown b/doc/api/events.markdown index 0afd583ebc..797b969ecc 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 396979a923..cc6f9516b5 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');