Skip to content

Commit

Permalink
[api] Add removeListenersByContext(context) method
Browse files Browse the repository at this point in the history
  • Loading branch information
onlywei committed Jul 29, 2018
1 parent 991b945 commit 3596eb1
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 0 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ differences:
- The `setMaxListeners`, `getMaxListeners`, `prependListener` and
`prependOnceListener` methods are not available.
- Support for custom context for events so there is no need to use `fn.bind`.
- There is an additional method named `removeListenersByContext`, which removes all listeners of the given
context.
- The `removeListener` method removes all matching listeners, not only the
first.

Expand Down Expand Up @@ -61,6 +63,9 @@ or `this` value that should be set for the emitted events. This means you no
longer have the overhead of an event that required `fn.bind` in order to get a
custom `this` value.

In addition to that, we have added a new method: `EventEmitter.removeListenersByContext`,
which will remove all listeners of the given context.

```js
var EE = new EventEmitter()
, context = { foo: 'bar' };
Expand All @@ -72,6 +77,7 @@ function emitted() {
EE.once('event-name', emitted, context);
EE.on('another-event', emitted, context);
EE.removeListener('another-event', emitted, context);
EE.removeListenersByContext(context);
```

### Tests and benchmarks
Expand Down
5 changes: 5 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ declare class EventEmitter<EventTypes extends string | symbol = string | symbol>
* Remove all listeners, or those of the specified event.
*/
removeAllListeners(event?: EventTypes): this;

/**
* Removes all listeners that were added with the specified context.
*/
removeListenersByContext(context?: any): this;
}

declare namespace EventEmitter {
Expand Down
32 changes: 32 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,38 @@ EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
return this;
};

/**
* Remove all listeners on a specific context.
*
* @param {*} context Only remove the listeners that have this context.
* @returns {EventEmitter} `this`.
* @public
*/
EventEmitter.prototype.removeListenersByContext = function removeListenersByContext(context) {
var eventNames = this.eventNames();
var totalListenerCount = 0;

for (var i = 0, eventsCount = eventNames.length; i < eventsCount; i++) {
var evt = eventNames[i];
var listeners = this._events[evt];

if (listeners.fn) listeners = [listeners];
for (var j = 0, events = [], listenersCount = listeners.length; j < listenersCount; j++) {
if (listeners[j].context !== context) events.push(listeners[j]);
}

if (events.length) {
this._events[evt] = events.length === 1 ? events[0] : events;
totalListenerCount += events.length;
} else {
clearEvent(this, evt);
}
}

this._eventsCount = totalListenerCount;
return this;
};

//
// Alias methods names because people roll like that.
//
Expand Down
29 changes: 29 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,35 @@ describe('EventEmitter', function tests() {
});
});

describe('EventEmitter#removeListenersByContext', function () {
it('removes all listeners for the specified context', function () {
var e = new EventEmitter();
var ctx1 = {};
var ctx2 = {};
var ctx3 = {};

e.on('aaa', function () { throw new Error('oops'); }, ctx1);
e.on('bbb', function () { throw new Error('oops'); }, ctx1);
e.on('aaa', function () { throw new Error('oops'); }, ctx2);
e.on('bbb', function () { throw new Error('oops'); }, ctx3);

assume(e.removeListenersByContext(ctx1)).equals(e);
assume(e.listeners('aaa').length).equals(1);
assume(e.listeners('bbb').length).equals(1);
assume(e._eventsCount).equals(2);

assume(e.removeListenersByContext(ctx2)).equals(e);
assume(e.listeners('aaa').length).equals(0);
assume(e.listeners('bbb').length).equals(1);
assume(e._eventsCount).equals(1);

assume(e.removeListenersByContext(ctx3)).equals(e);
assume(e.listeners('aaa').length).equals(0);
assume(e.listeners('bbb').length).equals(0);
assume(e._eventsCount).equals(0);
});
});

describe('EventEmitter#eventNames', function () {
it('returns an empty array when there are no events', function () {
var e = new EventEmitter();
Expand Down

0 comments on commit 3596eb1

Please sign in to comment.