Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editorial: expose "run steps after a timeout" #7349

Merged
merged 3 commits into from
Nov 24, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 91 additions & 50 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -93936,7 +93936,7 @@ import "https://example.com/foo/../module2.mjs";</code></pre>
</ol>
</li>

<li>
<li id="idle-deadline-computation">
<p>If all of the following are true

<ul class="brief">
Expand Down Expand Up @@ -96426,12 +96426,21 @@ enum <dfn enum>DOMParserSupportedType</dfn> {

<div w-nodev>

<p>Objects that implement the <code>WindowOrWorkerGlobalScope</code> mixin have a <dfn
export>map of active timers</dfn>, which is a <span>map</span>, initially empty. Each
<span data-x="map key">key</span> in this map is identified by a number, which must be unique
within the list for the lifetime of the object that implements the
<code>WindowOrWorkerGlobalScope</code> mixin, and each <span data-x="map value">value</span> is a
<code>DOMHighResTimeStamp</code>, representing the expiry time for that timer.</p>
<p>Objects that implement the <code>WindowOrWorkerGlobalScope</code> mixin have a <dfn>map of
active timers</dfn>, which is a <span>map</span>, initially empty. Each <span data-x="map
key">key</span> in this map is an identifier for a timer, and each <span data-x="map
value">value</span> is a <code>DOMHighResTimeStamp</code>, representing the expiry time for that
timer.</p>

<p class="note">For entries put in the <span>map of active timers</span> by the <span>timer
initialization steps</span>, i.e., by <code data-x="dom-setTimeout">setTimeout()</code> and <code
data-x="dom-setInterval">setInterval()</code>, the keys are numbers. For other specifications
that use the <span>run steps after a timeout</span> algorithm, the identifier is a unique
non-numeric value. Only the numeric-keyed timers are affected by <code
data-x="dom-clearTimeout">clearTimeout()</code> and <code
data-x="dom-clearInterval">clearInterval()</code>, but all timers contribute to <a
href="#idle-deadline-computation">idle deadline computation</a>, and are cleared when the
relevant global is destroyed.</p>

<hr>

Expand Down Expand Up @@ -96474,8 +96483,8 @@ enum <dfn enum>DOMParserSupportedType</dfn> {

<li><p>If <var>previousId</var> was given, let <var>id</var> be <var>previousId</var>;
otherwise, let <var>id</var> be an <span>implementation-defined</span> integer that is greater
than zero that will identify the timeout to be set by this call in <var>global</var>'s <span>map
of active timers</span>.</p></li>
than zero and does not already <span data-x="map exists">exist</span> in <var>global</var>'s
<span>map of active timers</span>.</p></li>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implies that a now-cleared ID can be reused, even if less than 2^31 timers have been created so far. But this is probably best left for #7358.


<li>
<p>If the <span>surrounding agent</span>'s <span data-x="concept-agent-event-loop">event
Expand Down Expand Up @@ -96580,50 +96589,19 @@ enum <dfn enum>DOMParserSupportedType</dfn> {

<li><p>Set <var>task</var>'s <dfn>timer nesting level</dfn> to <var>nesting level</var>.</p></li>

<li><p>Let <var>startTime</var> be the <span>current high resolution time</span>.</p></li>

<li><p><span data-x="map set">Set</span> <var>global</var>'s <span>map of active
timers</span>[<var>id</var>] to <var>startTime</var> plus <var>timeout</var>.</p></li>
<li><p>Let <var>completionStep</var> be an algorithm step which <span data-x="queue a global
task">queues a global task</span> on the <dfn export>timer task source</dfn> given
<var>global</var> to run <var>task</var>.</p></li>

<li>
<p>Run the following steps <span>in parallel</span>:</p>

<ol>
<li>
<p>If <var>global</var> is a <code>Window</code> object, wait until <var>global</var>'s <span
data-x="concept-document-window">associated <code>Document</code></span> has been <span>fully
active</span> for a further <var>timeout</var> milliseconds (not necessarily
consecutively).</p>

<p>Otherwise, <var>global</var> is a <code>WorkerGlobalScope</code> object; wait
until <var>timeout</var> milliseconds have passed with the worker not suspended (not
necessarily consecutively).</p>
</li>

<li><p>Wait until any invocations of this algorithm that had the same <var>global</var>, that
started before this one, and whose <var>timeout</var> is equal to or less than this one's,
have completed.</p></li>

<li>
<p>Optionally, wait a further <span>implementation-defined</span> length of time.</p>

<p class="note">This is intended to allow user agents to pad timeouts as needed to optimize
the power usage of the device. For example, some processors have a low-power mode where the
granularity of timers is reduced; on such platforms, user agents can slow timers down to fit
this schedule instead of requiring the processor to use the more accurate mode with its
associated higher power usage.</p>
</li>
<p><span>Run steps after a timeout</span> given <var>global</var>, "<code
data-x="">setTimeout/setInterval</code>", <var>timeout</var>, <var>completionStep</var>, and
<var>id</var>.</p>

<li>
<p><span>Queue a global task</span> on the <dfn>timer task source</dfn> given
<var>global</var> to run <var>task</var>.</p>

<p class="note">Once the task has been processed, if <var>repeat</var> is false, it is safe
to remove the entry for <var>id</var> from the <span>map of active timers</span> (there is no
way for the entry's existence to be detected past this point, so it does not technically
matter one way or the other).</p>
</li>
</ol>
<p class="note">Once the task has been processed, if <var>repeat</var> is false, it is safe to
remove the entry for <var>id</var> from the <span>map of active timers</span> (there is no way
for the entry's existence to be detected past this point, so it does not technically matter one
way or the other).</p>
</li>

<li><p>Return <var>id</var>.</p></li>
Expand Down Expand Up @@ -96675,6 +96653,69 @@ function scheduleWork() {
scheduleWork(); // queues a task to do lots of work</code></pre>
</div>

<div w-nodev>

<p>To <dfn export>run steps after a timeout</dfn>, given a <code>WindowOrWorkerGlobalScope</code>
<var>global</var>, a string <var>orderingIdentifier</var>, a number <var>milliseconds</var>, a
set of steps <var>completionSteps</var>, and an optional value <var>timerKey</var>:</p>

<ol>
<li><p>Assert: if <var>timerKey</var> is given, then the caller of this algorithm is the
<span>timer initialization steps</span>. (Other specifications must not pass
<var>timerKey</var>.)</p></li>

<li><p>If <var>timerKey</var> is not given, then set it to a new unique non-numeric
value.</p></li>

<li><p>Let <var>startTime</var> be the <span>current high resolution time</span>.</p></li>

<li><p><span data-x="map set">Set</span> <var>global</var>'s <span>map of active
timers</span>[<var>timerKey</var>] to <var>startTime</var> plus
<var>milliseconds</var>.</p></li>

<li>
<p>Run the following steps <span>in parallel</span>:</p>

<ol>
<li>
<p>If <var>global</var> is a <code>Window</code> object, wait until <var>global</var>'s <span
data-x="concept-document-window">associated <code>Document</code></span> has been <span>fully
active</span> for a further <var>milliseconds</var> milliseconds (not necessarily
consecutively).</p>

<p>Otherwise, <var>global</var> is a <code>WorkerGlobalScope</code> object; wait until
<var>milliseconds</var> milliseconds have passed with the worker not suspended (not
necessarily consecutively).</p>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this xref "active needed worker"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The interaction with the closing flag in https://html.spec.whatwg.org/#worker-processing-model:suspendable-worker makes me not 100% sure they are equivalent, so I'll leave it for now...

</li>

<li><p>Wait until any invocations of this algorithm that had the same <var>global</var> and
<var>orderingIdentifier</var>, that started before this one, and whose <var>milliseconds</var>
is equal to or less than this one's, have completed.</p></li>

<li>
<p>Optionally, wait a further <span>implementation-defined</span> length of time.</p>

<p class="note">This is intended to allow user agents to pad timeouts as needed to optimize
the power usage of the device. For example, some processors have a low-power mode where the
granularity of timers is reduced; on such platforms, user agents can slow timers down to fit
this schedule instead of requiring the processor to use the more accurate mode with its
associated higher power usage.</p>
</li>

<li><p>Perform <var>completionSteps</var>.</p></li>
</ol>
</li>
</ol>

<p class="note"><span>Run steps after a timeout</span> is meant to be used by other
specifications that want to execute developer-supplied code after a developer-supplied timeout,
in a similar manner to <code data-x="dom-setTimeout">setTimeout()</code>. (Note, however, it does
not have the nesting and clamping behavior of <code data-x="dom-setTimeout">setTimeout()</code>.)
Such specifications can choose an <var>orderingIdentifier</var> to ensure ordering within their
specification's timeouts, while not constraining ordering with respect to other specification's
timeouts.</p>

</div>

<h3>Microtask queuing</h3>

Expand Down