diff options
author | Benjamin Gruenbaum <benjamingr@gmail.com> | 2020-05-30 16:44:35 +0300 |
---|---|---|
committer | James M Snell <jasnell@gmail.com> | 2020-06-23 17:08:09 -0700 |
commit | 4b3654e923e7c3c2195c6809d52e65f77e5c4e92 (patch) | |
tree | ccacf4eef3c81fd0c0c504e0dbe7514adb753380 /lib/events.js | |
parent | 42d932c59bffe2f399759b8c7dd32e351ff144a3 (diff) | |
download | node-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.js | 84 |
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; |