From cc6deeaf7a3d4817df56565fc6e352415c62a7d2 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 817932a21d59c7..4f4c9f86a9874a 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -3364,7 +3364,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 c363e713a48902..48d239b60fb48c 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)` @@ -2462,7 +2469,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 32805d7aa10767..8e6a2b5af0ef54 100644 --- a/lib/events.js +++ b/lib/events.js @@ -835,17 +835,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);