summaryrefslogtreecommitdiff
path: root/lib/events.js
diff options
context:
space:
mode:
authorJames M Snell <jasnell@gmail.com>2020-08-24 13:11:23 -0700
committerNode.js GitHub Bot <github-bot@iojs.org>2020-08-31 15:09:57 +0000
commit883fc779b637732b18e2d0e6b1f386cebb37e93c (patch)
tree3451371d49699a9ce78550851a535c4bce435f42 /lib/events.js
parent37a8179673590af10b9e8e413388adffc21ba713 (diff)
downloadnode-new-883fc779b637732b18e2d0e6b1f386cebb37e93c.tar.gz
events: allow use of AbortController with once
Allows an AbortSignal to be passed in to events.once() to cancel waiting on an event. Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/34911 Reviewed-By: Denys Otrishko <shishugi@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Diffstat (limited to 'lib/events.js')
-rw-r--r--lib/events.js53
1 files changed, 52 insertions, 1 deletions
diff --git a/lib/events.js b/lib/events.js
index 48341c0b20..270588fcbc 100644
--- a/lib/events.js
+++ b/lib/events.js
@@ -44,6 +44,7 @@ const kRejection = SymbolFor('nodejs.rejection');
let spliceOne;
const {
+ hideStackFrames,
kEnhanceStackBeforeInspector,
codes
} = require('internal/errors');
@@ -57,9 +58,20 @@ const {
inspect
} = require('internal/util/inspect');
+const {
+ validateAbortSignal
+} = require('internal/validators');
+
const kCapture = Symbol('kCapture');
const kErrorMonitor = Symbol('events.errorMonitor');
+let DOMException;
+const lazyDOMException = hideStackFrames((message, name) => {
+ if (DOMException === undefined)
+ DOMException = internalBinding('messaging').DOMException;
+ return new DOMException(message, name);
+});
+
function EventEmitter(opts) {
EventEmitter.init.call(this, opts);
}
@@ -621,22 +633,61 @@ function unwrapListeners(arr) {
return ret;
}
-function once(emitter, name) {
+async function once(emitter, name, options = {}) {
+ const signal = options ? options.signal : undefined;
+ validateAbortSignal(signal, 'options.signal');
+ if (signal && signal.aborted)
+ throw lazyDOMException('The operation was aborted', 'AbortError');
return new Promise((resolve, reject) => {
const errorListener = (err) => {
emitter.removeListener(name, resolver);
+ if (signal != null) {
+ eventTargetAgnosticRemoveListener(
+ signal,
+ 'abort',
+ abortListener,
+ { once: true });
+ }
reject(err);
};
const resolver = (...args) => {
if (typeof emitter.removeListener === 'function') {
emitter.removeListener('error', errorListener);
}
+ if (signal != null) {
+ eventTargetAgnosticRemoveListener(
+ signal,
+ 'abort',
+ abortListener,
+ { once: true });
+ }
resolve(args);
};
eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
if (name !== 'error') {
addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });
}
+ function abortListener() {
+ if (typeof emitter.removeListener === 'function') {
+ emitter.removeListener(name, resolver);
+ emitter.removeListener('error', errorListener);
+ } else {
+ eventTargetAgnosticRemoveListener(
+ emitter,
+ name,
+ resolver,
+ { once: true });
+ eventTargetAgnosticRemoveListener(
+ emitter,
+ 'error',
+ errorListener,
+ { once: true });
+ }
+ reject(lazyDOMException('The operation was aborted', 'AbortError'));
+ }
+ if (signal != null) {
+ signal.addEventListener('abort', abortListener, { once: true });
+ }
});
}