From 2eb887549ac62b32900074658fbdff78e3c37a6a Mon Sep 17 00:00:00 2001 From: Paolo Insogna Date: Tue, 21 Feb 2023 02:38:51 -0800 Subject: [PATCH] events: add listener argument to listenerCount PR-URL: https://github.com/nodejs/node/pull/46523 Reviewed-By: Robert Nagy Reviewed-By: Matteo Collina Reviewed-By: Colin Ihrig Reviewed-By: Luigi Pinca Reviewed-By: James M Snell Reviewed-By: Moshe Atlow --- doc/api/deprecations.md | 2 +- doc/api/events.md | 13 +++-- lib/events.js | 19 ++++++- ...est-events-listener-count-with-listener.js | 53 +++++++++++++++++++ 4 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 test/parallel/test-events-listener-count-with-listener.js diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 64e27bf1afe9d1..7417817944e9be 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -3373,7 +3373,7 @@ In a future version of Node.js, [`message.headers`][], [`dnsPromises.lookup()`]: dns.md#dnspromiseslookuphostname-options [`domain`]: domain.md [`ecdh.setPublicKey()`]: crypto.md#ecdhsetpublickeypublickey-encoding -[`emitter.listenerCount(eventName)`]: events.md#emitterlistenercounteventname +[`emitter.listenerCount(eventName)`]: events.md#emitterlistenercounteventname-listener [`events.listenerCount(emitter, eventName)`]: events.md#eventslistenercountemitter-eventname [`fs.FileHandle`]: fs.md#class-filehandle [`fs.access()`]: fs.md#fsaccesspath-mode-callback diff --git a/doc/api/events.md b/doc/api/events.md index f31633772c1746..f1ee1de01121a1 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -646,16 +646,23 @@ Returns the current max listener value for the `EventEmitter` which is either set by [`emitter.setMaxListeners(n)`][] or defaults to [`events.defaultMaxListeners`][]. -### `emitter.listenerCount(eventName)` +### `emitter.listenerCount(eventName[, listener])` * `eventName` {string|symbol} The name of the event being listened for +* `listener` {Function} The event handler function * Returns: {integer} -Returns the number of listeners listening to the event named `eventName`. +Returns the number of listeners listening for the event named `eventName`. +If `listener` is provided, it will return how many times the listener is found +in the list of the listeners of the event. ### `emitter.listeners(eventName)` @@ -2482,7 +2489,7 @@ to the `EventTarget`. [`EventTarget` error handling]: #eventtarget-error-handling [`Event` Web API]: https://dom.spec.whatwg.org/#event [`domain`]: domain.md -[`emitter.listenerCount()`]: #emitterlistenercounteventname +[`emitter.listenerCount()`]: #emitterlistenercounteventname-listener [`emitter.removeListener()`]: #emitterremovelistenereventname-listener [`emitter.setMaxListeners(n)`]: #emittersetmaxlistenersn [`event.defaultPrevented`]: #eventdefaultprevented diff --git a/lib/events.js b/lib/events.js index 3d65432406c9ac..9e5c1100d8bc5d 100644 --- a/lib/events.js +++ b/lib/events.js @@ -834,17 +834,34 @@ EventEmitter.prototype.listenerCount = listenerCount; * Returns the number of listeners listening to event name * specified as `type`. * @param {string | symbol} type + * @param {Function} listener * @returns {number} */ -function listenerCount(type) { +function listenerCount(type, listener) { const events = this._events; if (events !== undefined) { const evlistener = events[type]; if (typeof evlistener === 'function') { + if (listener != null) { + return listener === evlistener ? 1 : 0; + } + return 1; } else if (evlistener !== undefined) { + if (listener != null) { + let matching = 0; + + for (let i = 0, l = evlistener.length; i < l; i++) { + if (evlistener[i] === listener || evlistener[i].listener === listener) { + matching++; + } + } + + return matching; + } + return evlistener.length; } } diff --git a/test/parallel/test-events-listener-count-with-listener.js b/test/parallel/test-events-listener-count-with-listener.js new file mode 100644 index 00000000000000..080ce6d704513e --- /dev/null +++ b/test/parallel/test-events-listener-count-with-listener.js @@ -0,0 +1,53 @@ +'use strict'; + +const common = require('../common'); +const EventEmitter = require('events'); +const assert = require('assert'); + +const EE = new EventEmitter(); +const handler = common.mustCall(undefined, 3); +const anotherHandler = common.mustCall(); + +assert.strictEqual(EE.listenerCount('event'), 0); +assert.strictEqual(EE.listenerCount('event', handler), 0); +assert.strictEqual(EE.listenerCount('event', anotherHandler), 0); + +EE.on('event', handler); + +assert.strictEqual(EE.listenerCount('event'), 1); +assert.strictEqual(EE.listenerCount('event', handler), 1); +assert.strictEqual(EE.listenerCount('event', anotherHandler), 0); + +EE.once('event', anotherHandler); + +assert.strictEqual(EE.listenerCount('event'), 2); +assert.strictEqual(EE.listenerCount('event', handler), 1); +assert.strictEqual(EE.listenerCount('event', anotherHandler), 1); + +assert.strictEqual(EE.listenerCount('another-event'), 0); +assert.strictEqual(EE.listenerCount('another-event', handler), 0); +assert.strictEqual(EE.listenerCount('another-event', anotherHandler), 0); + +EE.once('event', handler); + +assert.strictEqual(EE.listenerCount('event'), 3); +assert.strictEqual(EE.listenerCount('event', handler), 2); +assert.strictEqual(EE.listenerCount('event', anotherHandler), 1); + +EE.emit('event'); + +assert.strictEqual(EE.listenerCount('event'), 1); +assert.strictEqual(EE.listenerCount('event', handler), 1); +assert.strictEqual(EE.listenerCount('event', anotherHandler), 0); + +EE.emit('event'); + +assert.strictEqual(EE.listenerCount('event'), 1); +assert.strictEqual(EE.listenerCount('event', handler), 1); +assert.strictEqual(EE.listenerCount('event', anotherHandler), 0); + +EE.off('event', handler); + +assert.strictEqual(EE.listenerCount('event'), 0); +assert.strictEqual(EE.listenerCount('event', handler), 0); +assert.strictEqual(EE.listenerCount('event', anotherHandler), 0);