Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
fixup: on/removeListener
  • Loading branch information
ronag committed Sep 10, 2019
commit 7f4519018c1a5ed5a8ee825cdb8c0cb1f07e9c93
167 changes: 83 additions & 84 deletions doc/api/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -417,86 +417,8 @@ added: v10.0.0
* `listener` {Function}
* Returns: {EventEmitter}

Removes the specified `listener` from the listener array for the event named
`eventName`.

```js
const callback = (stream) => {
console.log('someone connected!');
};
server.on('connection', callback);
// ...
server.off('connection', callback);
```

`off()` will remove, at most, one instance of a listener from the
listener array. If any single listener has been added multiple times to the
listener array for the specified `eventName`, then `off()` must be
called multiple times to remove each instance.

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
`off()` 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();

const callbackA = () => {
console.log('A');
myEmitter.off('event', callbackB);
};

const callbackB = () => {
console.log('B');
};

myEmitter.on('event', callbackA);

myEmitter.on('event', callbackB);

// callbackA removes listener callbackB but it will still be called.
// Internal listener array at time of emit [callbackA, callbackB]
myEmitter.emit('event');
// Prints:
// A
// B

// callbackB is now removed.
// Internal 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,
but it means that any copies of the listener array as returned by
the `emitter.listeners()` method will need to be recreated.

When a single function has been added as a handler multiple times for a single
event (as in the example below), `off()` will remove the most
recently added instance. In the example the `once('ping')`
listener is removed:

```js
const ee = new EventEmitter();

function pong() {
console.log('pong');
}

ee.on('ping', pong);
ee.once('ping', pong);
ee.off('ping', pong);

ee.emit('ping');
ee.emit('ping');
```

Returns a reference to the `EventEmitter`, so that calls can be chained.
This function is implemented by calling [`emitter.removeListener()`][].
When overriding, override [`emitter.removeListener()`][].

### emitter.on(eventName, listener)
<!-- YAML
Expand Down Expand Up @@ -636,8 +558,86 @@ added: v0.1.26
* `listener` {Function}
* Returns: {EventEmitter}

This function is implemented by calling [`emitter.off()`][].
When overriding, override [`emitter.off()`][].
Removes the specified `listener` from the listener array for the event named
`eventName`.

```js
const callback = (stream) => {
console.log('someone connected!');
};
server.on('connection', callback);
// ...
server.removeListener('connection', callback);
```

`removeListener()` will remove, at most, one instance of a listener from the
listener array. If any single listener has been added multiple times to the
listener array for the specified `eventName`, then `removeListener()` must be
called multiple times to remove each instance.

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();

const callbackA = () => {
console.log('A');
myEmitter.removeListener('event', callbackB);
};

const callbackB = () => {
console.log('B');
};

myEmitter.on('event', callbackA);

myEmitter.on('event', callbackB);

// callbackA removes listener callbackB but it will still be called.
// Internal listener array at time of emit [callbackA, callbackB]
myEmitter.emit('event');
// Prints:
// A
// B

// callbackB is now removed.
// Internal 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,
but it means that any copies of the listener array as returned by
the `emitter.listeners()` method will need to be recreated.

When a single function has been added as a handler multiple times for a single
event (as in the example below), `removeListener()` will remove the most
recently added instance. In the example the `once('ping')`
listener is removed:

```js
const ee = new EventEmitter();

function pong() {
console.log('pong');
}

ee.on('ping', pong);
ee.once('ping', pong);
ee.removeListener('ping', pong);

ee.emit('ping');
ee.emit('ping');
```

Returns a reference to the `EventEmitter`, so that calls can be chained.

### emitter.setMaxListeners(n)
<!-- YAML
Expand Down Expand Up @@ -734,8 +734,7 @@ run();
[`EventEmitter.defaultMaxListeners`]: #events_eventemitter_defaultmaxlisteners
[`domain`]: domain.html
[`emitter.listenerCount()`]: #events_emitter_listenercount_eventname
[`emitter.on()`]: #events_emitter_on_eventname_listener
[`emitter.off()`]: #events_emitter_off_eventname_listener
[`emitter.removeListener()`]: #events_emitter_removelistener_eventname_listener
[`emitter.setMaxListeners(n)`]: #events_emitter_setmaxlisteners_n
[`fs.ReadStream`]: fs.html#fs_class_fs_readstream
[`net.Server`]: net.html#net_class_net_server
Expand Down
4 changes: 2 additions & 2 deletions lib/_stream_readable.js
Original file line number Diff line number Diff line change
Expand Up @@ -898,8 +898,8 @@ Readable.prototype.on = function(ev, fn) {
return res;
};

Readable.prototype.off = function(ev, fn) {
const res = Stream.prototype.off.call(this, ev, fn);
Readable.prototype.removeListener = function(ev, fn) {
const res = Stream.prototype.removeListener.call(this, ev, fn);

if (ev === 'readable') {
// We need to check if there is someone still listening to
Expand Down
10 changes: 5 additions & 5 deletions lib/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,8 @@ EventEmitter.prototype.prependOnceListener =
};

// Emits a 'removeListener' event if and only if the listener was removed.
EventEmitter.prototype.off =
function off(type, listener) {
EventEmitter.prototype.removeListener =
function removeListener(type, listener) {
let originalListener;

checkListener(listener);
Expand Down Expand Up @@ -380,9 +380,9 @@ EventEmitter.prototype.off =
return this;
};

EventEmitter.prototype.removeListener =
function removeListener(type, listener) {
return this.off(type, listener);
EventEmitter.prototype.off =
function off(type, listener) {
return this.removeListener(type, listener);
};

EventEmitter.prototype.removeAllListeners =
Expand Down
4 changes: 2 additions & 2 deletions test/parallel/test-events-override.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ const { EventEmitter: EE } = require('events');

{
const e = new EE();
e.off = common.mustCall();
e.removeListener('test', () => {});
e.removeListener = common.mustCall();
e.off('test', () => {});
}