summaryrefslogtreecommitdiff
path: root/lib/events.js
diff options
context:
space:
mode:
authorBenjamin Gruenbaum <benjamingr@gmail.com>2020-05-30 16:44:35 +0300
committerJames M Snell <jasnell@gmail.com>2020-06-23 17:08:09 -0700
commit4b3654e923e7c3c2195c6809d52e65f77e5c4e92 (patch)
treeccacf4eef3c81fd0c0c504e0dbe7514adb753380 /lib/events.js
parent42d932c59bffe2f399759b8c7dd32e351ff144a3 (diff)
downloadnode-new-4b3654e923e7c3c2195c6809d52e65f77e5c4e92.tar.gz
events: fix EventTarget support
Remove support for multiple arguments (which don't actually work for EventTarget). Use our EventTarget implementation rather than a mock. Refactor `once` code in preparation of `on` using shared code for supporting `on` with `EventTarget`s. Support EventTarget in the `events.on` static method PR-URL: https://github.com/nodejs/node/pull/34015 Reviewed-By: Denys Otrishko <shishugi@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Diffstat (limited to 'lib/events.js')
-rw-r--r--lib/events.js84
1 files changed, 49 insertions, 35 deletions
diff --git a/lib/events.js b/lib/events.js
index 51259e6821..48341c0b20 100644
--- a/lib/events.js
+++ b/lib/events.js
@@ -623,41 +623,20 @@ function unwrapListeners(arr) {
function once(emitter, name) {
return new Promise((resolve, reject) => {
- if (typeof emitter.addEventListener === 'function') {
- // EventTarget does not have `error` event semantics like Node
- // EventEmitters, we do not listen to `error` events here.
- emitter.addEventListener(
- name,
- (...args) => { resolve(args); },
- { once: true }
- );
- return;
- }
-
- const eventListener = (...args) => {
- if (errorListener !== undefined) {
+ const errorListener = (err) => {
+ emitter.removeListener(name, resolver);
+ reject(err);
+ };
+ const resolver = (...args) => {
+ if (typeof emitter.removeListener === 'function') {
emitter.removeListener('error', errorListener);
}
resolve(args);
};
- let errorListener;
-
- // Adding an error listener is not optional because
- // if an error is thrown on an event emitter we cannot
- // guarantee that the actual event we are waiting will
- // be fired. The result could be a silent way to create
- // memory or file descriptor leaks, which is something
- // we should avoid.
+ eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
if (name !== 'error') {
- errorListener = (err) => {
- emitter.removeListener(name, eventListener);
- reject(err);
- };
-
- emitter.once('error', errorListener);
+ addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });
}
-
- emitter.once(name, eventListener);
});
}
@@ -668,6 +647,38 @@ function createIterResult(value, done) {
return { value, done };
}
+function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
+ if (typeof emitter.on === 'function') {
+ eventTargetAgnosticAddListener(emitter, 'error', handler, flags);
+ }
+}
+
+function eventTargetAgnosticRemoveListener(emitter, name, listener, flags) {
+ if (typeof emitter.removeListener === 'function') {
+ emitter.removeListener(name, listener);
+ } else if (typeof emitter.removeEventListener === 'function') {
+ emitter.removeEventListener(name, listener, flags);
+ } else {
+ throw new ERR_INVALID_ARG_TYPE('emitter', 'EventEmitter', emitter);
+ }
+}
+
+function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
+ if (typeof emitter.on === 'function') {
+ if (flags && flags.once) {
+ emitter.once(name, listener);
+ } else {
+ emitter.on(name, listener);
+ }
+ } else if (typeof emitter.addEventListener === 'function') {
+ // EventTarget does not have `error` event semantics like Node
+ // EventEmitters, we do not listen to `error` events here.
+ emitter.addEventListener(name, (arg) => { listener(arg); }, flags);
+ } else {
+ throw new ERR_INVALID_ARG_TYPE('emitter', 'EventEmitter', emitter);
+ }
+}
+
function on(emitter, event) {
const unconsumedEvents = [];
const unconsumedPromises = [];
@@ -704,8 +715,8 @@ function on(emitter, event) {
},
return() {
- emitter.removeListener(event, eventHandler);
- emitter.removeListener('error', errorHandler);
+ eventTargetAgnosticRemoveListener(emitter, event, eventHandler);
+ eventTargetAgnosticRemoveListener(emitter, 'error', errorHandler);
finished = true;
for (const promise of unconsumedPromises) {
@@ -721,8 +732,8 @@ function on(emitter, event) {
'Error', err);
}
error = err;
- emitter.removeListener(event, eventHandler);
- emitter.removeListener('error', errorHandler);
+ eventTargetAgnosticRemoveListener(emitter, event, eventHandler);
+ eventTargetAgnosticRemoveListener(emitter, 'error', errorHandler);
},
[SymbolAsyncIterator]() {
@@ -730,8 +741,11 @@ function on(emitter, event) {
}
}, AsyncIteratorPrototype);
- emitter.on(event, eventHandler);
- emitter.on('error', errorHandler);
+ eventTargetAgnosticAddListener(emitter, event, eventHandler);
+ if (event !== 'error') {
+ addErrorHandlerIfEventEmitter(emitter, errorHandler);
+ }
+
return iterator;