-
Notifications
You must be signed in to change notification settings - Fork 47
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
Improve the run-to-completion principle. #536
Conversation
index.bs
Outdated
* Functions meant to help developers interrupt synchronous work, | ||
as in the case of the proposed {{isInputPending()}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feature is somewhat controversial because it violates run-to-completion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels reasonable to drop this reference. The other examples are enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The TAG is on record supporting this exception in w3ctag/design-reviews#415 (comment) and w3ctag/design-reviews#475 (comment) (cc @dbaron for any historical context). I can break this into a separate PR if we need to discuss it more, but this function seems to be a case of putting authors ahead of technical purity. There might also be a better phrasing to explain what makes this exception acceptable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's historical, maybe clarify this? MDN says this isInputPending is "superseded".
This guide is for new APIs, and as it reads, suggests "Functions meant to help developers interrupt synchronous work" is a legit reason. As general advice this might lead to new APIs that through blocking turn async calls into synchronous ones, which currently isn't possible AFAIK (a design invariant?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. Apparently IdleDeadline.timeRemaining() also adjusts to help developers stop their idle work if other tasks appear, and it's in a WG and shipped in 2 engines. I'll switch to that example.
* Functions meant to help developers interrupt synchronous work, | |
as in the case of the proposed {{isInputPending()}}. | |
* Functions meant to help developers interrupt synchronous work, | |
as in the case of {{IdleDeadline/timeRemaining()|IdleDeadline.timeRemaining()}}. |
I've filed w3c/requestidlecallback#104 because the spec doesn't call this out as clearly as I'd hope. I'm also not sure the name as clear about the unusual behavior as isInputPending
was: do folks want to include advice that a better name would have been ideal, and if so, what name?
index.bs
Outdated
* Functions meant to help developers interrupt synchronous work, | ||
as in the case of the proposed {{isInputPending()}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels reasonable to drop this reference. The other examples are enough.
Generally LGTM! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the reviews!
index.bs
Outdated
* Functions meant to help developers interrupt synchronous work, | ||
as in the case of the proposed {{isInputPending()}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The TAG is on record supporting this exception in w3ctag/design-reviews#415 (comment) and w3ctag/design-reviews#475 (comment) (cc @dbaron for any historical context). I can break this into a separate PR if we need to discuss it more, but this function seems to be a case of putting authors ahead of technical purity. There might also be a better phrasing to explain what makes this exception acceptable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For what it's worth, I'm generally supportive of these changes. I think the core of this principle is about preventing surprising behavior and preventing broken code that results from that surprise. In that vein, the clearer it is that the functions have this sort of behavior, the better. (For example, it's reasonably clear that something like Date.now()
might change as slow code executes.)
For things that do violate this, we want it to be pretty clear that code (conceptually, maybe not syntactically) like this is bad:
if (window.isPurple) {
// (1)
} else {
// (2)
}
// ...
if (window.isPurple) {
// assume path (1) above executed
}
f45db0c
to
45b4ea4
Compare
Don't modify data accessed via JavaScript APIs | ||
while a JavaScript <a>event loop</a> is running. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that we need a positive statement for this principle.
Maybe
Propagate changes to state
that originate outside of JavaScript execution context
between tasks, not within them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, or maybe by moving up the "a task should be queued" suggestion below...
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=].
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How's this? I also simplified the next paragraph, and focused it on async changes instead of claiming that https://html.spec.whatwg.org/multipage/webappapis.html#killing-scripts doesn't exist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this looks like a great improvement to me!
I'd like to continue to discuss #496 separately for a little bit if that's OK, but that doesn't need to block this. It may be redundant, but I'd like to double-check there isn't a principle there worth describing specific to designing promise-returning APIs that come with synchronous requirements.
* {{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 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is "changes" refers not only to readable properties, but any state changes that might trip up the developer's code execution, like the observable behavior of a method they invoke. Should we add an example of that? Maybe something like:
* A method acting differently depending on which [=microtask=] it is called on. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, good point that we should specifically include changes in method behavior. I think the wording you've suggested implies that folks might be tempted to identify microtasks, which they generally aren't, so I'd like to call out a particular function. I had trouble finding a synchronous method that does actually change behavior depending on queued changes, and ones that return Promises can always return in a new task, so I think I have to use a counterfactual:
* 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. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A method acting differently depending on which [=microtask=] it is called on.
fwiw, a close example of this is requestAnimationFrame
. It makes sense that it sometimes runs the callback before the next frame, and sometimes after, but it's annoying that you don't know which of these will happen. whatwg/html#10113
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I can see a similar principle that requestAnimationFrame
could violate, but all of the bits of the event loop transition on task boundaries, so it's not this principle. I didn't even mis-write this part of the example, since the rendering stages don't advance asynchronously. :)
Is this maybe a new principle for the HTML section that method behavior shouldn't depend on the event loop stage? Except that's not exactly what you're looking for in that issue since you're asking for a way to detect the stage rather than a method that behaves consistently. Could this be just "design requestAnimationFrame
with the benefit of hindsight" rather than a generalizable principle?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, honestly, I think my example shows that:
A method acting differently depending on which [=microtask=] it is called on.
…isn't the right terminology.
I think requestAnimationFrame
is ok, it's just missing that bit that tells you in advance if it'll run before or after the next frame.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. I think that means https://w3ctag.github.io/design-principles/#js-rtc is basically correct, and there's nothing more for me to do on this PR. Let me know or file an issue if I have that wrong. :)
index.bs
Outdated
* Functions meant to help developers interrupt synchronous work, | ||
as in the case of the proposed {{isInputPending()}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's historical, maybe clarify this? MDN says this isInputPending is "superseded".
This guide is for new APIs, and as it reads, suggests "Functions meant to help developers interrupt synchronous work" is a legit reason. As general advice this might lead to new APIs that through blocking turn async calls into synchronous ones, which currently isn't possible AFAIK (a design invariant?)
* "While an event loop is running" wasn't the right period to limit changes. * We have a list of exceptions to this principle.
Co-authored-by: Martin Thomson <[email protected]>
… the middle of a statement.
Co-authored-by: Martin Thomson <[email protected]>
da0caea
to
483f437
Compare
* 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.
Co-authored-by: Jan-Ivar Bruaroey <[email protected]>
ae181b3
to
7a896a6
Compare
This can be reverted once WICG/shared-storage#212 is merged and crawled.
SHA: c63b666 Reason: push, by martinthomson Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This is meant to fix #456; @jakearchibald, can you check it? Thank you for the text!
I think this also supersedes #496. @jan-ivar, have I caught everything you meant to say there?
Preview | Diff