events: getEventListeners static

PR-URL: https://github.com/nodejs/node/pull/35991
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
Benjamin Gruenbaum authored and Node.js GitHub Bot committed 2020-11-09 07:39:31 +00:00
1 parent ad98cf04f3
commit 1a6d4dce6d
4 files changed
+97 -1

No files matched your search

+34
View File
@@ -829,6 +829,40 @@ class MyClass extends EventEmitter {
}
```
## `events.getEventListeners(emitterOrTarget, eventName)`
<!-- YAML
added:
- REPLACEME
-->
* `emitterOrTarget` {EventEmitter|EventTarget}
* `eventName` {string|symbol}
* Returns: {Function[]}
Returns a copy of the array of listeners for the event named `eventName`.
For `EventEmitter`s this behaves exactly the same as calling `.listeners` on
the emitter.
For `EventTarget`s this is the only way to get the event listeners for the
event target. This is useful for debugging and diagnostic purposes.
```js
const { getEventListeners, EventEmitter } = require('events');
{
const ee = new EventEmitter();
const listener = () => console.log('Events are fun');
ee.on('foo', listener);
getEventListeners(ee, 'foo'); // [listener]
}
{
const et = new EventTarget();
const listener = () => console.log('Events are fun');
ee.addEventListener('foo', listener);
getEventListeners(ee, 'foo'); // [listener]
}
```
## `events.once(emitter, name[, options])`
<!-- YAML
added:
+25 -1
View File
@@ -22,6 +22,7 @@
'use strict';
const {
ArrayPrototypePush,
Boolean,
Error,
ErrorCaptureStackTrace,
@@ -74,13 +75,14 @@ const lazyDOMException = hideStackFrames((message, name) => {
return new DOMException(message, name);
});
function EventEmitter(opts) {
EventEmitter.init.call(this, opts);
}
module.exports = EventEmitter;
module.exports.once = once;
module.exports.on = on;
module.exports.getEventListeners = getEventListeners;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
@@ -634,6 +636,28 @@ function unwrapListeners(arr) {
return ret;
}
function getEventListeners(emitterOrTarget, type) {
// First check if EventEmitter
if (typeof emitterOrTarget.listeners === 'function') {
return emitterOrTarget.listeners(type);
}
// Require event target lazily to avoid always loading it
const { isEventTarget, kEvents } = require('internal/event_target');
if (isEventTarget(emitterOrTarget)) {
const root = emitterOrTarget[kEvents].get(type);
const listeners = [];
let handler = root?.next;
while (handler?.listener !== undefined) {
ArrayPrototypePush(listeners, handler.listener);
handler = handler.next;
}
return listeners;
}
throw new ERR_INVALID_ARG_TYPE('emitter',
['EventEmitter', 'EventTarget'],
emitterOrTarget);
}
async function once(emitter, name, options = {}) {
const signal = options ? options.signal : undefined;
validateAbortSignal(signal, 'options.signal');
+2
View File
@@ -636,4 +636,6 @@ module.exports = {
kNewListener,
kTrustEvent,
kRemoveListener,
kEvents,
isEventTarget,
};
@@ -0,0 +1,36 @@
'use strict';
const common = require('../common');
const {
deepStrictEqual,
} = require('assert');
const { getEventListeners, EventEmitter } = require('events');
// Test getEventListeners on EventEmitter
{
const fn1 = common.mustNotCall();
const fn2 = common.mustNotCall();
const emitter = new EventEmitter();
emitter.on('foo', fn1);
emitter.on('foo', fn2);
emitter.on('baz', fn1);
emitter.on('baz', fn1);
deepStrictEqual(getEventListeners(emitter, 'foo'), [fn1, fn2]);
deepStrictEqual(getEventListeners(emitter, 'bar'), []);
deepStrictEqual(getEventListeners(emitter, 'baz'), [fn1, fn1]);
}
// Test getEventListeners on EventTarget
{
const fn1 = common.mustNotCall();
const fn2 = common.mustNotCall();
const target = new EventTarget();
target.addEventListener('foo', fn1);
target.addEventListener('foo', fn2);
target.addEventListener('baz', fn1);
target.addEventListener('baz', fn1);
deepStrictEqual(getEventListeners(target, 'foo'), [fn1, fn2]);
deepStrictEqual(getEventListeners(target, 'bar'), []);
deepStrictEqual(getEventListeners(target, 'baz'), [fn1]);
}