summaryrefslogtreecommitdiff
path: root/ext/web/03_abort_signal.js
diff options
context:
space:
mode:
authorAndreu Botella <andreu@andreubotella.com>2022-03-14 20:19:22 +0100
committerGitHub <noreply@github.com>2022-03-14 20:19:22 +0100
commit9f494dc405afc4b1b29fa4c813bd5751f26aaa36 (patch)
tree2757ee74fe3f5e9e134e1265bc71d87febc63d32 /ext/web/03_abort_signal.js
parent5eb0e4c2dfab4b83fbc69746d8e1143f78e9154e (diff)
feat(ext/web): Add `AbortSignal.timeout()` (#13687)
Diffstat (limited to 'ext/web/03_abort_signal.js')
-rw-r--r--ext/web/03_abort_signal.js44
1 files changed, 44 insertions, 0 deletions
diff --git a/ext/web/03_abort_signal.js b/ext/web/03_abort_signal.js
index 8b089d031..39de8d0fc 100644
--- a/ext/web/03_abort_signal.js
+++ b/ext/web/03_abort_signal.js
@@ -7,6 +7,7 @@
((window) => {
const webidl = window.__bootstrap.webidl;
const { setIsTrusted, defineEventHandler } = window.__bootstrap.event;
+ const { listenerCount } = window.__bootstrap.eventTarget;
const {
Set,
SetPrototypeAdd,
@@ -14,6 +15,7 @@
Symbol,
TypeError,
} = window.__bootstrap.primordials;
+ const { setTimeout, refTimer, unrefTimer } = window.__bootstrap.timers;
const add = Symbol("[[add]]");
const signalAbort = Symbol("[[signalAbort]]");
@@ -21,6 +23,7 @@
const abortReason = Symbol("[[abortReason]]");
const abortAlgos = Symbol("[[abortAlgos]]");
const signal = Symbol("[[signal]]");
+ const timerId = Symbol("[[timerId]]");
const illegalConstructorKey = Symbol("illegalConstructorKey");
@@ -34,6 +37,27 @@
return signal;
}
+ static timeout(millis) {
+ const prefix = "Failed to call 'AbortSignal.timeout'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ millis = webidl.converters["unsigned long long"](millis, {
+ enforceRange: true,
+ });
+
+ const signal = new AbortSignal(illegalConstructorKey);
+ signal[timerId] = setTimeout(
+ () => {
+ signal[timerId] = null;
+ signal[signalAbort](
+ new DOMException("Signal timed out.", "TimeoutError"),
+ );
+ },
+ millis,
+ );
+ unrefTimer(signal[timerId]);
+ return signal;
+ }
+
[add](algorithm) {
if (this.aborted) {
return;
@@ -73,6 +97,7 @@
super();
this[abortReason] = undefined;
this[abortAlgos] = null;
+ this[timerId] = null;
this[webidl.brand] = webidl.brand;
}
@@ -92,6 +117,25 @@
throw this[abortReason];
}
}
+
+ // `addEventListener` and `removeEventListener` have to be overriden in
+ // order to have the timer block the event loop while there are listeners.
+ // `[add]` and `[remove]` don't ref and unref the timer because they can
+ // only be used by Deno internals, which use it to essentially cancel async
+ // ops which would block the event loop.
+ addEventListener(...args) {
+ super.addEventListener(...args);
+ if (this[timerId] !== null && listenerCount(this, "abort") > 0) {
+ refTimer(this[timerId]);
+ }
+ }
+
+ removeEventListener(...args) {
+ super.removeEventListener(...args);
+ if (this[timerId] !== null && listenerCount(this, "abort") === 0) {
+ unrefTimer(this[timerId]);
+ }
+ }
}
defineEventHandler(AbortSignal.prototype, "abort");