From 54a8d8bb685c18fdd5dfa26ee311bb16a0eec400 Mon Sep 17 00:00:00 2001
From: Andreu Botella User agents that support JavaScript must also implement the AsyncContext proposal.
+ The following terms are defined there, and used in this specification: JSASYNCCONTEXT[Global][PropagatesAsyncContext][LegacyFactoryFunction][LegacyLenientThis][LegacyNullToEmptyString]
+
template element
section.
To run an + algorithm steps with an Async Context Mapping mapping: + JSASYNCCONTEXT
+ +Let previousMapping be + AsyncContextSwap(mapping).
Let returnValue be the result of running steps. If this throws an + exception e, then:
+ +Perform AsyncContextSwap(previousMapping).
Throw e.
Perform AsyncContextSwap(previousMapping).
Return returnValue.
Specifications should not use the AsyncContextSwap abstract operation defined in + JSASYNCCONTEXT, or otherwise set or mutate an agent record's [[AsyncContextMapping]] + field. Instead they should run an algorithm with + an Async Context Mapping, which properly cleans up after itself.
+ @@ -66678,6 +66723,10 @@ o............A....eA script element has a delaying the
load event boolean, initially false.
A script element has an execution Async Context Mapping, which is
+ either null or an Async Context Mapping, initially null. It is used so async-local
+ state from the script preparation is available when the script is executed.
A script element has a type, which is
either null, "classic", "module", "importmap", or "speculationrules", initially null. It is
@@ -67184,6 +67233,9 @@ document.body.append(script1, script2);
+
Set el's execution Async Context Mapping to + AsyncContextSnapshot().
If el does not have a src content
attribute:
script element el:
Let document be el's node document.
Assert: el's execution Async Context Mapping is not + null.
If el's preparation-time document is not equal to - document, then return.
Run the following steps with + el's execution Async Context Mapping:
-Unblock rendering on el.
In the case where prepare the script element + immediately invoked this algorithm, this does not change the current Async + Context Mapping.
-If el's result is null, then fire an event named error
- at el, and return.
Set el's execution Async Context Mapping to null.
If el's from an external file is
- true, or el's type is "module", then increment document's ignore-destructive-writes
- counter.
Let document be el's node document.
Switch on el's type:
+If el's preparation-time document is not equal to + document, then return.
classic"Let oldCurrentScript be the value to which document's currentScript object was most recently
- set.
Unblock rendering on el.
If el's root is not a shadow root, then
- set document's currentScript
- attribute to el. Otherwise, set it to null.
This does not use the in a document tree check, as
- el could have been removed from the document prior to execution, and in that
- scenario currentScript still needs to
- point to it.
If el's result is null, then fire an event named error
+ at el, and return.
Run the classic script given by - el's result.
If el's from an external file is
+ true, or el's type is "module", then increment document's ignore-destructive-writes
+ counter.
Set document's currentScript attribute to
- oldCurrentScript.
Switch on el's type:
-module"Assert: document's currentScript attribute is null.
classic"Let oldCurrentScript be the value to which document's currentScript object was most recently
+ set.
Run the module script given by - el's result.
If el's root is not a shadow root, then
+ set document's currentScript
+ attribute to el. Otherwise, set it to null.
This does not use the in a document tree check, as
+ el could have been removed from the document prior to execution, and in that
+ scenario currentScript still needs to
+ point to it.
importmap"Register an import map given el's relevant global - object and el's result.
Run the classic script given by + el's result.
speculationrules"Register speculation rules given el's relevant global - object and el's result.
Set document's currentScript attribute to
+ oldCurrentScript.
Decrement the ignore-destructive-writes counter of document, if - it was incremented in the earlier step.
module"Assert: document's currentScript attribute is null.
If el's from an external file is
- true, then fire an event named load at el.
Run the module script given by + el's result.
importmap"Register an import map given el's relevant global + object and el's result.
speculationrules"Register speculation rules given el's relevant global + object and el's result.
Decrement the ignore-destructive-writes counter of document, if + it was incremented in the earlier step.
If el's from an external file is
+ true, then fire an event named load at el.
If blur event target is not null, fire a focus event
- named blur at blur event target, with
- related blur target as the related target.
If blur event target is not null:
+ +If blur event target's relevant agent is not the + surrounding agent, or if blur event target's relevant settings + object's origin is not + same origin with the current settings object's origin, then run the following steps with Async Context Mapping « ». + Otherwise, run the following steps:
+ +Fire a focus event named blur at
+ blur event target, with related blur target as the related
+ target.
Issue #3506: If + focus event target's relevant agent is not the surrounding agent, then the event + should be fired in a task in the relevant agent's event loop.
+ +In some cases, e.g., if entry is
an area element's shape, a scrollable region, or a viewport, no
@@ -85428,9 +85517,30 @@ dictionary CommandEventInit : EventInit {
focus target be null.
If focus event target is not null, fire a focus event
- named focus at focus event target, with
- related focus target as the related target.
If focus event target is not null:
+ +If focus event target's relevant agent is not the + surrounding agent, or if focus event target's relevant + settings object's origin is not + same origin with the current settings object's origin, then run the following steps with Async Context Mapping « ». + Otherwise, run the following steps:
+ +Fire a focus event named focus at
+ focus event target, with related focus target as the related
+ target.
Issue #3506: If + focus event target's relevant agent is not the surrounding agent, then the event + should be fired in a task in the relevant agent's event loop.
+ +In some cases, e.g. if entry is an area
element's shape, a scrollable region, or a viewport, no event is fired.
While the event loop's microtask queue is not empty:
+Run the following steps with Async + Context Mapping « »:
Let oldestMicrotask be the result of dequeuing - from the event loop's microtask queue.
While the event loop's microtask queue is not empty:
-Set the event loop's currently running task to - oldestMicrotask.
Let oldestMicrotask be the result of dequeuing + from the event loop's microtask queue.
Run oldestMicrotask.
+Set the event loop's currently running task to + oldestMicrotask.
Run oldestMicrotask.
+ +This might involve invoking scripted callbacks, which eventually calls the + clean up after running script steps, which call this perform a microtask + checkpoint algorithm again, which is why we use the performing a microtask + checkpoint flag to avoid reentrancy.
+This might involve invoking scripted callbacks, which eventually calls the - clean up after running script steps, which call this perform a microtask - checkpoint algorithm again, which is why we use the performing a microtask - checkpoint flag to avoid reentrancy.
+Set the event loop's currently running task back to + null.
Set the event loop's currently running task back to - null.
For each environment settings object settingsObject whose + responsible event loop is this event loop, notify about rejected + promises given settingsObject's global object.
For each environment settings object settingsObject whose - responsible event loop is this event loop, notify about rejected - promises given settingsObject's global object.
Cleanup Indexed Database transactions.
Let uniqueHandle be null.
Let savedAsyncContextMapping be AsyncContextSnapshot().
Let task be a task that runs the following substeps:
Assert: uniqueHandle is a unique internal value, - not null.
Run the following steps with the + Async Context Mapping savedAsyncContextMapping: -
If id does not exist in global's - map of setTimeout and setInterval IDs, then abort these steps.
Assert: uniqueHandle is a unique internal value, + not null.
If global's map of setTimeout and setInterval IDs[id] - does not equal uniqueHandle, then abort these steps.
- -This accommodates for the ID having been cleared by a clearTimeout() or clearInterval() call, and being reused by a subsequent
- setTimeout() or setInterval() call.
If id does not exist in global's + map of setTimeout and setInterval IDs, then abort these steps.
Let settings object be global's relevant settings - object.
If global's map of setTimeout and setInterval IDs[id] + does not equal uniqueHandle, then abort these steps.
+ +This accommodates for the ID having been cleared by a clearTimeout() or clearInterval() call, and being reused by a subsequent
+ setTimeout() or setInterval() call.
If scripting is disabled for - settings object, then abort these steps.
Let settings object be global's relevant settings + object.
Record timing info for timer handler given handler, - settings object, and repeat.
If scripting is disabled for + settings object, then abort these steps.
If handler is a Function, then invoke handler given
- arguments and "report", and with callback this value set to thisArg.
Record timing info for timer handler given handler, + settings object, and repeat.
Otherwise:
+If handler is a Function, then invoke handler given
+ arguments and "report", and with callback this value set to thisArg.
If previousId was not given:
+Otherwise:
Let globalName be "Window" if global is
- a Window object; "WorkerGlobalScope"
- otherwise.
If previousId was not given:
-Let methodName be "setInterval" if
- repeat is true; "setTimeout" otherwise.
Let globalName be "Window" if global is
+ a Window object; "WorkerGlobalScope"
+ otherwise.
Let sink be a concatenation of globalName, U+0020 SPACE, and - methodName.
Let methodName be "setInterval" if
+ repeat is true; "setTimeout" otherwise.
Set handler to the result of invoking the get trusted type compliant string algorithm with
- TrustedScript, global,
- handler, sink, and "script".
Let sink be a concatenation of globalName, U+0020 SPACE, and + methodName.
Set handler to the result of invoking the get trusted type compliant string algorithm with
+ TrustedScript, global,
+ handler, sink, and "script".
Assert: handler is a string.
Assert: handler is a string.
Perform EnsureCSPDoesNotBlockStringCompilation(realm, - « », handler, handler, timer, « », handler). If this throws - an exception, catch it, report it for - global, and abort these steps.
Perform EnsureCSPDoesNotBlockStringCompilation(realm, + « », handler, handler, timer, « », handler). If this throws + an exception, catch it, report it for + global, and abort these steps.
Let fetch options be the default script fetch - options.
Let fetch options be the default script fetch + options.
Let base URL be settings object's API base - URL.
Let base URL be settings object's API base + URL.
If initiating script is not null, then:
+If initiating script is not null, then:
-Set fetch options to a script fetch options whose cryptographic nonce is initiating
- script's fetch options's
- cryptographic nonce, integrity metadata is the empty
- string, parser metadata is
- "not-parser-inserted", credentials mode is
- initiating script's fetch
- options's credentials
- mode, referrer
- policy is initiating script's fetch options's referrer policy, and fetch priority is "auto".
Set base URL to initiating script's base URL.
Set fetch options to a script fetch options whose cryptographic nonce is initiating
+ script's fetch options's
+ cryptographic nonce, integrity metadata is the empty
+ string, parser metadata is
+ "not-parser-inserted", credentials mode is
+ initiating script's fetch
+ options's credentials
+ mode, referrer
+ policy is initiating script's fetch options's referrer policy, and fetch priority is "auto".
Set base URL to initiating script's base URL.
The effect of these steps ensures that the string compilation done by setTimeout() and setInterval() behaves equivalently to that done by
- eval(). That is, module script fetches via import()
- will behave the same in both contexts.
The effect of these steps ensures that the string compilation done by setTimeout() and setInterval() behaves equivalently to that done by
+ eval(). That is, module script fetches via import()
+ will behave the same in both contexts.
Let script be the result of creating a classic script given - handler, settings object, base URL, and fetch - options.
Let script be the result of creating a classic script given + handler, settings object, base URL, and fetch + options.
Run the classic script - script.
Run the classic script + script.
If id does not exist in global's - map of setTimeout and setInterval IDs, then abort these steps.
If id does not exist in global's + map of setTimeout and setInterval IDs, then abort these steps.
If global's map of setTimeout and setInterval IDs[id] - does not equal uniqueHandle, then abort these steps.
- -The ID might have been removed via the author code in handler
- calling clearTimeout() or clearInterval(). Checking that uniqueHandle isn't different
- accounts for the possibility of the ID, after having been cleared, being reused by a
- subsequent setTimeout() or setInterval() call.
If global's map of setTimeout and setInterval IDs[id] + does not equal uniqueHandle, then abort these steps.
+ +The ID might have been removed via the author code in handler
+ calling clearTimeout() or clearInterval(). Checking that uniqueHandle isn't different
+ accounts for the possibility of the ID, after having been cleared, being reused by a
+ subsequent setTimeout() or setInterval() call.
If repeat is true, then perform the timer initialization - steps again, given global, handler, timeout, - arguments, true, and id.
If repeat is true, then perform the timer initialization + steps again, given global, handler, timeout, + arguments, true, and id.
Otherwise, remove global's map of - setTimeout and setInterval IDs[id].
Otherwise, remove global's map of + setTimeout and setInterval IDs[id].
callback FrameRequestCallback = undefined (DOMHighResTimeStamp time);
interface mixin AnimationFrameProvider {
- unsigned long requestAnimationFrame(FrameRequestCallback callback);
+ unsigned long requestAnimationFrame([PropagatesAsyncContext] FrameRequestCallback callback);
undefined cancelAnimationFrame(unsigned long handle);
};
Window includes AnimationFrameProvider;
@@ -155976,6 +156102,9 @@ INSERT INTERFACES HERE
[JPEG]
JPEG File Interchange Format, E. Hamilton.
+ [JSASYNCCONTEXT]
+ AsyncContext. Ecma International.
+
[JSERRORSTACKS]
(Non-normative) Error Stacks. Ecma International.
From 015923ac2b1e1b032cb367af1688a820a2b7ca1f Mon Sep 17 00:00:00 2001
From: Andreu Botella
Date: Thu, 12 Feb 2026 16:06:51 +0100
Subject: [PATCH 2/2] Inline run inside the timer task
---
source | 224 ++++++++++++++++++++++++++++-----------------------------
1 file changed, 109 insertions(+), 115 deletions(-)
diff --git a/source b/source
index ad8c1b70682..5e79d3f0b0b 100644
--- a/source
+++ b/source
@@ -125034,150 +125034,144 @@ interface XMLSerializer {
Let savedAsyncContextMapping be AsyncContextSnapshot().
- Let task be a task that runs the following
- substeps:
+ Let task be a task that runs the following steps with the Async Context Mapping
+ savedAsyncContextMapping:
- -
-
Run the following steps with the
- Async Context Mapping savedAsyncContextMapping:
+
Assert: uniqueHandle is a unique internal value,
+ not null.
-
- Assert: uniqueHandle is a unique internal value,
- not null.
+ If id does not exist in global's
+ map of setTimeout and setInterval IDs, then abort these steps.
- If id does not exist in global's
- map of setTimeout and setInterval IDs, then abort these steps.
+ -
+
If global's map of setTimeout and setInterval IDs[id]
+ does not equal uniqueHandle, then abort these steps.
+
+ This accommodates for the ID having been cleared by a clearTimeout() or clearInterval() call, and being reused by a subsequent
+ setTimeout() or setInterval() call.
+
- -
-
If global's map of setTimeout and setInterval IDs[id]
- does not equal uniqueHandle, then abort these steps.
-
- This accommodates for the ID having been cleared by a clearTimeout() or clearInterval() call, and being reused by a subsequent
- setTimeout() or setInterval() call.
-
+ Let settings object be global's relevant settings
+ object.
- Let settings object be global's relevant settings
- object.
+ If scripting is disabled for
+ settings object, then abort these steps.
- If scripting is disabled for
- settings object, then abort these steps.
+ Record timing info for timer handler given handler,
+ settings object, and repeat.
- Record timing info for timer handler given handler,
- settings object, and repeat.
+ If handler is a Function, then invoke handler given
+ arguments and "report", and with callback this value set to thisArg.
- If handler is a Function, then invoke handler given
- arguments and "report", and with callback this value set to thisArg.
+ -
+
Otherwise:
+
-
-
Otherwise:
+ If previousId was not given:
- -
-
If previousId was not given:
-
-
- Let globalName be "Window" if global is
- a Window object; "WorkerGlobalScope"
- otherwise.
-
- Let methodName be "setInterval" if
- repeat is true; "setTimeout" otherwise.
-
- Let sink be a concatenation of globalName, U+0020 SPACE, and
- methodName.
-
- Set handler to the result of invoking the get trusted type compliant string algorithm with
- TrustedScript, global,
- handler, sink, and "script".
-
-
+ Let globalName be "Window" if global is
+ a Window object; "WorkerGlobalScope"
+ otherwise.
- Assert: handler is a string.
+ Let methodName be "setInterval" if
+ repeat is true; "setTimeout" otherwise.
- Perform EnsureCSPDoesNotBlockStringCompilation(realm,
- « », handler, handler, timer, « », handler). If this throws
- an exception, catch it, report it for
- global, and abort these steps.
-
+ Let sink be a concatenation of globalName, U+0020 SPACE, and
+ methodName.
- Let fetch options be the default script fetch
- options.
+ Set handler to the result of invoking the get trusted type compliant string algorithm with
+ TrustedScript, global,
+ handler, sink, and "script".
+
+
- Let base URL be settings object's API base
- URL.
+ Assert: handler is a string.
- -
-
If initiating script is not null, then:
+ Perform EnsureCSPDoesNotBlockStringCompilation(realm,
+ « », handler, handler, timer, « », handler). If this throws
+ an exception, catch it, report it for
+ global, and abort these steps.
+
-
- Set fetch options to a script fetch options whose cryptographic nonce is initiating
- script's fetch options's
- cryptographic nonce, integrity metadata is the empty
- string, parser metadata is
- "not-parser-inserted", credentials mode is
- initiating script's fetch
- options's credentials
- mode, referrer
- policy is initiating script's fetch options's referrer policy, and fetch priority is "auto".
-
- Set base URL to initiating script's base URL.
-
+ Let fetch options be the default script fetch
+ options.
- The effect of these steps ensures that the string compilation done by setTimeout() and setInterval() behaves equivalently to that done by
- eval(). That is, module script fetches via import()
- will behave the same in both contexts.
-
+ Let base URL be settings object's API base
+ URL.
- Let script be the result of creating a classic script given
- handler, settings object, base URL, and fetch
- options.
+ -
+
If initiating script is not null, then:
- Run the classic script
- script.
+
+ Set fetch options to a script fetch options whose cryptographic nonce is initiating
+ script's fetch options's
+ cryptographic nonce, integrity metadata is the empty
+ string, parser metadata is
+ "not-parser-inserted", credentials mode is
+ initiating script's fetch
+ options's credentials
+ mode, referrer
+ policy is initiating script's fetch options's referrer policy, and fetch priority is "auto".
+
+ Set base URL to initiating script's base URL.
-
-
- If id does not exist in global's
- map of setTimeout and setInterval IDs, then abort these steps.
-
- If global's map of setTimeout and setInterval IDs[id]
- does not equal uniqueHandle, then abort these steps.
-
- The ID might have been removed via the author code in handler
- calling clearTimeout() or clearInterval(). Checking that uniqueHandle isn't different
- accounts for the possibility of the ID, after having been cleared, being reused by a
- subsequent setTimeout() or setInterval() call.
+ The effect of these steps ensures that the string compilation done by setTimeout() and setInterval() behaves equivalently to that done by
+ eval(). That is, module script fetches via import()
+ will behave the same in both contexts.
- If repeat is true, then perform the timer initialization
- steps again, given global, handler, timeout,
- arguments, true, and id.
+ Let script be the result of creating a classic script given
+ handler, settings object, base URL, and fetch
+ options.
- Otherwise, remove global's map of
- setTimeout and setInterval IDs[id].
+ Run the classic script
+ script.
+
+ If id does not exist in global's
+ map of setTimeout and setInterval IDs, then abort these steps.
+
+
+ If global's map of setTimeout and setInterval IDs[id]
+ does not equal uniqueHandle, then abort these steps.
+
+ The ID might have been removed via the author code in handler
+ calling clearTimeout() or clearInterval(). Checking that uniqueHandle isn't different
+ accounts for the possibility of the ID, after having been cleared, being reused by a
+ subsequent setTimeout() or setInterval() call.
+
+
+ If repeat is true, then perform the timer initialization
+ steps again, given global, handler, timeout,
+ arguments, true, and id.
+
+ Otherwise, remove global's map of
+ setTimeout and setInterval IDs[id].