Skip to content

Commit c63b666

Browse files
jyasskinmartinthomsonjan-ivar
authored
Improve the run-to-completion principle. (#536)
* Improve the run-to-completion principle. * "While an event loop is running" wasn't the right period to limit changes. * We have a list of exceptions to this principle. * Warn against letting an attribute change in the middle of a statement. * Apply Martin's suggestions. Co-authored-by: Martin Thomson <[email protected]> * Remove a redundant sentence of emphasis on not changing attributes in the middle of a statement. * Be more general than `while true`. Co-authored-by: Martin Thomson <[email protected]> * Move a positive statement to the top of the principle. * Remove irrelevant and incorrect claims. * It doesn't matter whether JS is a wrapper around code in another language. * JS doesn't always get to complete: users can kill it. * Apply changes resulting from Jan-Ivar's code review Co-authored-by: Jan-Ivar Bruaroey <[email protected]> * Identify which LockManager. This can be reverted once WICG/shared-storage#212 is merged and crawled. --------- Co-authored-by: Martin Thomson <[email protected]> Co-authored-by: Jan-Ivar Bruaroey <[email protected]>
1 parent 6c1568b commit c63b666

File tree

1 file changed

+48
-19
lines changed

1 file changed

+48
-19
lines changed

index.bs

+48-19
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ spec:webidl
4747
type:idl; text:long
4848
type:idl; text:short
4949
type:interface; text:double
50+
spec:web-locks; type:interface; text:LockManager
5051
</pre>
5152
<pre class='ignored-specs'>
5253
spec: css21
@@ -1437,34 +1438,62 @@ to have bindings in other programming languages.
14371438

14381439
<h3 id="js-rtc">Preserve run-to-completion semantics</h3>
14391440

1440-
Don't modify data accessed via JavaScript APIs
1441-
while a JavaScript <a>event loop</a> is running.
1442-
1443-
A JavaScript Web API is generally a wrapper around
1444-
a feature implemented in a lower-level language,
1445-
such as C++ or Rust.
1446-
Unlike those languages,
1447-
when using JavaScript developers can expect
1448-
that once a piece of code begins executing,
1449-
it will continue executing until it has completed.
1441+
If a change to state originates outside of the JavaScript execution context,
1442+
propagate that change to JavaScript between tasks,
1443+
for example by [[html#queuing-tasks|queuing a task]],
1444+
or as part of [=update the rendering=].
14501445

1446+
Unlike lower-level languages
1447+
such as C++ or Rust,
1448+
JavaScript has historically acted as if
1449+
only one piece of code can execute at once.
14511450
Because of that, JavaScript authors take for granted
14521451
that the data available to a function won’t change unexpectedly
14531452
while the function is running.
14541453

1455-
So if a JavaScript Web API exposes some piece of data,
1456-
such as an object property,
1457-
the user agent must not update that data
1458-
while a JavaScript task is running.
1459-
Instead, if the underlying data changes,
1460-
<a>queue a task</a> to modify the exposed version of the data.
1454+
Changes that are not the result of developer action
1455+
and changes that are asynchronously delivered
1456+
should not happen in the middle of other JavaScript,
1457+
including between [=microtasks=].
14611458

14621459
<div class="example">
1463-
If a JavaScript task has accessed the {{NavigatorOnline/onLine|navigator.onLine}} property,
1464-
and browser's online status changes,
1465-
the property won't be updated until the next task runs.
1460+
During synchronous execution (such as a `while` loop),
1461+
and after `await`ing an already-resolved `Promise`,
1462+
developers are *unlikely* to expect things like:
1463+
1464+
* The DOM to update as a result of the HTML parser loading new content from the network
1465+
* {{HTMLImageElement/width|img.width}} to change as a result of loading image data from the network
1466+
* Buttons of a {{Gamepad}} to change state
1467+
* {{Element/scrollTop}} to change, even if scrolling can visually occur
1468+
* A synchronous method to act differently depending on asynchronous state changes.
1469+
For example, if {{LockManager}} had synchronous methods,
1470+
their behavior would depend on concurrent calls in other windows.
1471+
1472+
These things aren't updated by the currently running script,
1473+
so they shouldn't change during the current task.
1474+
14661475
</div>
14671476

1477+
Data can update synchronously from the result of developer action.
1478+
1479+
<div class="example">
1480+
{{ChildNode/remove()|node.remove()}} changes the DOM synchronously
1481+
and is immediately observable.
1482+
</div>
1483+
1484+
A few kinds of situations justify violating this rule:
1485+
1486+
* Observing the current time,
1487+
as in {{Date/now|Date.now()}} and {{Performance/now|performance.now()}},
1488+
although note that it's also useful to present a consistent task-wide time
1489+
as in {{AnimationTimeline/currentTime|document.timeline.currentTime}}.
1490+
* Functions meant to help developers interrupt synchronous work,
1491+
as in the case of {{IdleDeadline/timeRemaining()|IdleDeadline.timeRemaining()}}.
1492+
* States meant to protect users from surprising UI changes,
1493+
like [=transient activation=].
1494+
Note that {{UserActivation/isActive|navigator.userActivation.isActive}}
1495+
violates [[#attributes-like-data|the guidance that recommends a method for this case]].
1496+
14681497
<h3 id="js-gc">Don't expose garbage collection</h3>
14691498

14701499
Ensure your JavaScript Web APIs don't provide a way

0 commit comments

Comments
 (0)