From d892efa0dbcced08548bdfc82f3b203e48469113 Mon Sep 17 00:00:00 2001 From: Jeffrey Yasskin Date: Fri, 6 Dec 2024 13:33:38 +0000 Subject: [PATCH 1/9] 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. --- index.bs | 48 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/index.bs b/index.bs index 747c9c2c..808add7b 100644 --- a/index.bs +++ b/index.bs @@ -1437,9 +1437,6 @@ to have bindings in other programming languages.

Preserve run-to-completion semantics

-Don't modify data accessed via JavaScript APIs -while a JavaScript event loop is running. - A JavaScript Web API is generally a wrapper around a feature implemented in a lower-level language, such as C++ or Rust. @@ -1452,19 +1449,46 @@ Because of that, JavaScript authors take for granted that the data available to a function won’t change unexpectedly while the function is running. -So if a JavaScript Web API exposes some piece of data, -such as an object property, -the user agent must not update that data -while a JavaScript task is running. -Instead, if the underlying data changes, -queue a task to modify the exposed version of the data. +Changes that are not the result of developer action +and changes that are asynchronously delivered +should not happen in the middle of other JavaScript, +including between [=microtasks=]. +Instead, a task should be [[html#queuing-tasks|queued]], +or they should update as part of [=update the rendering=]. + +
+During a `while (true)`, +and after `await`ing an already-resolved `Promise`, +you *shouldn't* expect things like: + +* The DOM to update as a result of the HTML parser loading network content +* {{HTMLImageElement/width|img.width}} to change as a result of loading image data from the network +* Buttons of a {{Gamepad}} to change state +* {{Element/scrollTop}} to change, even if scrolling can visually occur + +These things aren't updated by the currently running script, +so they shouldn't change during the current task. + +
+ +Data can update synchronously from the result of developer action.
-If a JavaScript task has accessed the {{NavigatorOnline/onLine|navigator.onLine}} property, -and browser's online status changes, -the property won't be updated until the next task runs. +{{ChildNode/remove()|node.remove()}} changes the DOM synchronously +and is immediately observable.
+A few kinds of situations justify violating this rule: + +* Observing the current time, + as in {{Date/now|Date.now()}} and {{Performance/now|performance.now()}}, + although note that it's also useful to present a consistent task-wide time + as in {{AnimationTimeline/currentTime|document.timeline.currentTime}}. +* Functions meant to help developers interrupt synchronous work, + as in the case of the proposed {{isInputPending()}}. +* States meant to protect users from surprising UI changes, + like [=transient activation=]. +

Don't expose garbage collection

Ensure your JavaScript Web APIs don't provide a way From 4b0c9054798171e00118dcdc2c41a4d7d8e58489 Mon Sep 17 00:00:00 2001 From: Jeffrey Yasskin Date: Sun, 8 Dec 2024 19:46:46 +0000 Subject: [PATCH 2/9] Warn against letting an attribute change in the middle of a statement. --- index.bs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 808add7b..4e916fe7 100644 --- a/index.bs +++ b/index.bs @@ -1478,7 +1478,10 @@ Data can update synchronously from the result of developer action. and is immediately observable. -A few kinds of situations justify violating this rule: +A few kinds of situations justify violating this rule. +In these cases, +be sure to [[#attributes-like-data|expose values as methods rather than attributes +if they might change in the middle of a JS statement]]. * Observing the current time, as in {{Date/now|Date.now()}} and {{Performance/now|performance.now()}}, @@ -1488,6 +1491,8 @@ A few kinds of situations justify violating this rule: as in the case of the proposed {{isInputPending()}}. * States meant to protect users from surprising UI changes, like [=transient activation=]. + Note that {{UserActivation/isActive|navigator.userActivation.isActive}} + violates [[#attributes-like-data]] and should not.

Don't expose garbage collection

From 420d7ac659a6554156c36d081debaa02004f6353 Mon Sep 17 00:00:00 2001 From: Jeffrey Yasskin Date: Mon, 9 Dec 2024 09:34:04 -0800 Subject: [PATCH 3/9] Apply Martin's suggestions. Co-authored-by: Martin Thomson --- index.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index 4e916fe7..5cf70bff 100644 --- a/index.bs +++ b/index.bs @@ -1461,7 +1461,7 @@ During a `while (true)`, and after `await`ing an already-resolved `Promise`, you *shouldn't* expect things like: -* The DOM to update as a result of the HTML parser loading network content +* The DOM to update as a result of the HTML parser loading new content from the network * {{HTMLImageElement/width|img.width}} to change as a result of loading image data from the network * Buttons of a {{Gamepad}} to change state * {{Element/scrollTop}} to change, even if scrolling can visually occur @@ -1492,7 +1492,7 @@ if they might change in the middle of a JS statement]]. * States meant to protect users from surprising UI changes, like [=transient activation=]. Note that {{UserActivation/isActive|navigator.userActivation.isActive}} - violates [[#attributes-like-data]] and should not. + violates [[#attributes-like-data|the guidance that recommends a method for this case]].

Don't expose garbage collection

From 0875e3075d46438c654441d04ff6060ff702ab9a Mon Sep 17 00:00:00 2001 From: Jeffrey Yasskin Date: Wed, 11 Dec 2024 23:14:58 -0800 Subject: [PATCH 4/9] Remove a redundant sentence of emphasis on not changing attributes in the middle of a statement. --- index.bs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/index.bs b/index.bs index 5cf70bff..5f0208b1 100644 --- a/index.bs +++ b/index.bs @@ -1478,10 +1478,7 @@ Data can update synchronously from the result of developer action. and is immediately observable. -A few kinds of situations justify violating this rule. -In these cases, -be sure to [[#attributes-like-data|expose values as methods rather than attributes -if they might change in the middle of a JS statement]]. +A few kinds of situations justify violating this rule: * Observing the current time, as in {{Date/now|Date.now()}} and {{Performance/now|performance.now()}}, From 483f4373cbd3bd9e4b6192c240c62ed7a5cb4669 Mon Sep 17 00:00:00 2001 From: Jeffrey Yasskin Date: Thu, 12 Dec 2024 22:03:54 -0800 Subject: [PATCH 5/9] Be more general than `while true`. Co-authored-by: Martin Thomson --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 5f0208b1..61eedceb 100644 --- a/index.bs +++ b/index.bs @@ -1457,7 +1457,7 @@ Instead, a task should be [[html#queuing-tasks|queued]], or they should update as part of [=update the rendering=].
-During a `while (true)`, +During synchronous execution (such as a `while` loop), and after `await`ing an already-resolved `Promise`, you *shouldn't* expect things like: From 088ec62c81796792add3f374ec1e36edc343c287 Mon Sep 17 00:00:00 2001 From: Jeffrey Yasskin Date: Tue, 17 Dec 2024 20:43:33 +0000 Subject: [PATCH 6/9] Move a positive statement to the top of the principle. --- index.bs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index 61eedceb..8e0f5284 100644 --- a/index.bs +++ b/index.bs @@ -1437,6 +1437,11 @@ to have bindings in other programming languages.

Preserve run-to-completion semantics

+If a change to state originates outside of the JavaScript execution context, +propagate that change to JavaScript between tasks, +for example by [[html#queuing-tasks|queuing a task]], +or as part of [=update the rendering=]. + A JavaScript Web API is generally a wrapper around a feature implemented in a lower-level language, such as C++ or Rust. @@ -1453,8 +1458,6 @@ Changes that are not the result of developer action and changes that are asynchronously delivered should not happen in the middle of other JavaScript, including between [=microtasks=]. -Instead, a task should be [[html#queuing-tasks|queued]], -or they should update as part of [=update the rendering=].
During synchronous execution (such as a `while` loop), From 4ea05e17b3c29f0939e851c3a20a323d09b01b8c Mon Sep 17 00:00:00 2001 From: Jeffrey Yasskin Date: Tue, 17 Dec 2024 21:15:21 +0000 Subject: [PATCH 7/9] 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. --- index.bs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/index.bs b/index.bs index 8e0f5284..ae30e02f 100644 --- a/index.bs +++ b/index.bs @@ -1442,14 +1442,10 @@ propagate that change to JavaScript between tasks, for example by [[html#queuing-tasks|queuing a task]], or as part of [=update the rendering=]. -A JavaScript Web API is generally a wrapper around -a feature implemented in a lower-level language, -such as C++ or Rust. -Unlike those languages, -when using JavaScript developers can expect -that once a piece of code begins executing, -it will continue executing until it has completed. - +Unlike lower-level languages +such as C++ or Rust, +JavaScript has historically acted as if +only one piece of code can execute at once. Because of that, JavaScript authors take for granted that the data available to a function won’t change unexpectedly while the function is running. From 7a896a6bcc923ec6922fdc59a2efc5b5e058dec3 Mon Sep 17 00:00:00 2001 From: Jeffrey Yasskin Date: Tue, 17 Dec 2024 14:16:19 -0800 Subject: [PATCH 8/9] Apply changes resulting from Jan-Ivar's code review Co-authored-by: Jan-Ivar Bruaroey --- index.bs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index ae30e02f..b4e502ea 100644 --- a/index.bs +++ b/index.bs @@ -1458,12 +1458,15 @@ including between [=microtasks=].
During synchronous execution (such as a `while` loop), and after `await`ing an already-resolved `Promise`, -you *shouldn't* expect things like: +developers are *unlikely* to expect things like: * The DOM to update as a result of the HTML parser loading new content from the network * {{HTMLImageElement/width|img.width}} to change as a result of loading image data from the network * Buttons of a {{Gamepad}} to change state * {{Element/scrollTop}} to change, even if scrolling can visually occur +* A synchronous method to act differently depending on asynchronous state changes. + For example, if {{LockManager}} had synchronous methods, + their behavior would depend on concurrent calls in other windows. These things aren't updated by the currently running script, so they shouldn't change during the current task. @@ -1484,7 +1487,7 @@ A few kinds of situations justify violating this rule: although note that it's also useful to present a consistent task-wide time as in {{AnimationTimeline/currentTime|document.timeline.currentTime}}. * Functions meant to help developers interrupt synchronous work, - as in the case of the proposed {{isInputPending()}}. + as in the case of {{IdleDeadline/timeRemaining()|IdleDeadline.timeRemaining()}}. * States meant to protect users from surprising UI changes, like [=transient activation=]. Note that {{UserActivation/isActive|navigator.userActivation.isActive}} From 21262c9c5b4d5f2424e7354e8a993bb4174d4a6a Mon Sep 17 00:00:00 2001 From: Jeffrey Yasskin Date: Tue, 17 Dec 2024 22:25:16 +0000 Subject: [PATCH 9/9] Identify which LockManager. This can be reverted once https://github.com/WICG/shared-storage/pull/212 is merged and crawled. --- index.bs | 1 + 1 file changed, 1 insertion(+) diff --git a/index.bs b/index.bs index b4e502ea..3dcc0462 100644 --- a/index.bs +++ b/index.bs @@ -47,6 +47,7 @@ spec:webidl type:idl; text:long type:idl; text:short type:interface; text:double +spec:web-locks; type:interface; text:LockManager
 spec: css21