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

Use DOM's post-insertion steps for <script> elements #10188

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

domfarolino
Copy link
Member

@domfarolino domfarolino commented Mar 8, 2024

This PR (part 1 of probably 2) uses the newly-introduced DOM Standard "post-insertion steps" (see whatwg/dom#1261), which are run for all nodes in a batch of freshly-inserted nodes, after all DOM insertions take place. The purpose of these steps is to provide an opportunity for script executing side effects to take place during the insertion flow, but after after all DOM mutations are completed atomically. This PR effectively supersedes a portion of #4354.

Before this PR, the HTML standard executed scripts during the <script> HTML element insertion steps. This means that when a batch of script elements were "atomically" inserted, each script would run synchronously after its DOM insertion and before the next DOM insertion took place.

After this PR, to make progress on whatwg/dom#808 and move to a more "atomic" model where script execution only takes place after all pending DOM tree insertions happen, script execution moves to a model that more closely resembles that of Chromium and Firefox. We push script execution back to the post-insertion steps, which run after all DOM insertions are complete. This gives two notable observables differences from the old spec:

  1. All text nodes atomically inserted as children to a script will run when their parent script executes. Imagine you have an empty parser-inserted script element. Before this PR, doing script.append(new Text("..."), new Text("..."), ...) would "prepare" and "execute" the script synchronously after the first text node was inserted, because HTML says that whenever a child element is inserted to a connected script element, that's when the script gets prepared. All subsequent text nodes that are appended as children would come after the script has already started, so they would not execute. What I think the standard really means though, is to count on the script's "children changed steps" that DOM offers. After this PR, the execution of script is run after the entire batch of children get inserted, because the execution is tied to the "children changed steps", which run after all nodes are inserted. Therefore, execution would include all text that was atomically added to the script. This is tested here; Safari is the odd one out (I guess because it's not using the "children changed steps" properly?)
  2. The post-insertion steps run after a parent's "children changed steps" run. This means any nested <script> elements inserted as children to a parent <script> element will run (as a result of its "post-insertion steps") after the parent script gets a chance at running (as a result of its "children changed steps", which run before any post-insertion steps). See this concrete example I added in the spec. This has a WPT too, but it assumes a blend of the old a new models (which forced nested script execution before parent script execution). I'm updating it to match this spec, in DOM: Correct script-in-script atomic move WPT expectations web-platform-tests/wpt#45094.

(See WHATWG Working Mode: Changes for more details.)


/infrastructure.html ( diff )
/scripting.html ( diff )

@domfarolino domfarolino marked this pull request as ready for review March 8, 2024 19:48
@domfarolino domfarolino requested a review from annevk March 8, 2024 19:48
@@ -1796,6 +1795,18 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
<span>node document</span>.</p></li>
</ol>

<p>The <span data-x="concept-node-post-insert-ext">post-insertion steps</span> for the HTML
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm just following the lead of the insertion steps, where we override them once for this specification, and fan them out into element-specific ones. I notice we don't do that for "children changed steps" though (each element just uses that dfn directly, with no HTML middle-man). Not sure what's more desirable?

source Show resolved Hide resolved
@domfarolino
Copy link
Member Author

/cc @noamr @mfreed7

chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Mar 13, 2024
Given the old Chromium change that introduced this behavior:
 - https://source.chromium.org/chromium/chromium/src/+/604e798ec6ee30f44d57a5c4a44ce3dab3a871ed

... the old discussion in:
 - whatwg/dom#732 (review)
 - whatwg/html#4354 (comment)

... and the much newer discussion in:
 - whatwg/dom#1261
 - whatwg/html#10188

This CL upstreams an old test ensuring that removal of a child node
from a script node that has not "already started" [1], does not trigger
script execution. Only the *insertion* of child nodes (to a
non-already-started script node) should trigger that script's execution.

[1]: https://html.spec.whatwg.org/C#already-started

[email protected]

Bug: 40150299
Change-Id: I750ccee0a2be834360c557042e975547c8ddd32c
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Mar 13, 2024
Given the old Chromium change that introduced this behavior:
 - https://source.chromium.org/chromium/chromium/src/+/604e798ec6ee30f44d57a5c4a44ce3dab3a871ed

... the old discussion in:
 - whatwg/dom#732 (review)
 - whatwg/html#4354 (comment)

... and the much newer discussion in:
 - whatwg/dom#1261
 - whatwg/html#10188

This CL upstreams an old test ensuring that removal of a child node
from a script node that has not "already started" [1], does not trigger
script execution. Only the *insertion* of child nodes (to a
non-already-started script node) should trigger that script's execution.

[1]: https://html.spec.whatwg.org/C#already-started

[email protected]

Bug: 40150299
Change-Id: I750ccee0a2be834360c557042e975547c8ddd32c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5367238
Reviewed-by: Noam Rosenthal <[email protected]>
Commit-Queue: Dominic Farolino <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1272330}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Mar 13, 2024
Given the old Chromium change that introduced this behavior:
 - https://source.chromium.org/chromium/chromium/src/+/604e798ec6ee30f44d57a5c4a44ce3dab3a871ed

... the old discussion in:
 - whatwg/dom#732 (review)
 - whatwg/html#4354 (comment)

... and the much newer discussion in:
 - whatwg/dom#1261
 - whatwg/html#10188

This CL upstreams an old test ensuring that removal of a child node
from a script node that has not "already started" [1], does not trigger
script execution. Only the *insertion* of child nodes (to a
non-already-started script node) should trigger that script's execution.

[1]: https://html.spec.whatwg.org/C#already-started

[email protected]

Bug: 40150299
Change-Id: I750ccee0a2be834360c557042e975547c8ddd32c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5367238
Reviewed-by: Noam Rosenthal <[email protected]>
Commit-Queue: Dominic Farolino <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1272330}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Mar 13, 2024
This CL corrects the script-in-script insertion test, to assert that
when an "outer" script element (that has not yet been prepared/executed)
gets an "inner" script element inserted into it, the outer script runs
before the inner one.

This is a break in what the HTML Standard previously required, before
whatwg/html#10188.

[email protected]

Bug: 40150299
Change-Id: If8cdce18a13678ac0646d81bc14850b2f26b6eb7
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Mar 13, 2024
This CL corrects the script-in-script insertion test, to assert that
when an "outer" script element (that has not yet been prepared/executed)
gets an "inner" script element inserted into it, the outer script runs
before the inner one.

This is a break in what the HTML Standard previously required, before
whatwg/html#10188.

[email protected]

Bug: 40150299
Change-Id: If8cdce18a13678ac0646d81bc14850b2f26b6eb7
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Mar 14, 2024
This CL corrects the script-in-script insertion test, to assert that
when an "outer" script element (that has not yet been prepared/executed)
gets an "inner" script element inserted into it, the outer script runs
before the inner one.

This is a break in what the HTML Standard previously required, before
whatwg/html#10188.

[email protected]

Bug: 40150299
Change-Id: If8cdce18a13678ac0646d81bc14850b2f26b6eb7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5367667
Reviewed-by: Noam Rosenthal <[email protected]>
Commit-Queue: Dominic Farolino <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1272720}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Mar 14, 2024
This CL corrects the script-in-script insertion test, to assert that
when an "outer" script element (that has not yet been prepared/executed)
gets an "inner" script element inserted into it, the outer script runs
before the inner one.

This is a break in what the HTML Standard previously required, before
whatwg/html#10188.

[email protected]

Bug: 40150299
Change-Id: If8cdce18a13678ac0646d81bc14850b2f26b6eb7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5367667
Reviewed-by: Noam Rosenthal <[email protected]>
Commit-Queue: Dominic Farolino <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1272720}
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this pull request Mar 15, 2024
…er execution, a=testonly

Automatic update from web-platform-tests
WPT: Script child removal does not trigger execution

Given the old Chromium change that introduced this behavior:
 - https://source.chromium.org/chromium/chromium/src/+/604e798ec6ee30f44d57a5c4a44ce3dab3a871ed

... the old discussion in:
 - whatwg/dom#732 (review)
 - whatwg/html#4354 (comment)

... and the much newer discussion in:
 - whatwg/dom#1261
 - whatwg/html#10188

This CL upstreams an old test ensuring that removal of a child node
from a script node that has not "already started" [1], does not trigger
script execution. Only the *insertion* of child nodes (to a
non-already-started script node) should trigger that script's execution.

[1]: https://html.spec.whatwg.org/C#already-started

[email protected]

Bug: 40150299
Change-Id: I750ccee0a2be834360c557042e975547c8ddd32c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5367238
Reviewed-by: Noam Rosenthal <[email protected]>
Commit-Queue: Dominic Farolino <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1272330}

--

wpt-commits: cc99c62762135f7e193941e32c3f738960c256be
wpt-pr: 45085
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this pull request Mar 15, 2024
…e WPT expectations, a=testonly

Automatic update from web-platform-tests
DOM: Correct script-in-script atomic move WPT expectations

This CL corrects the script-in-script insertion test, to assert that
when an "outer" script element (that has not yet been prepared/executed)
gets an "inner" script element inserted into it, the outer script runs
before the inner one.

This is a break in what the HTML Standard previously required, before
whatwg/html#10188.

[email protected]

Bug: 40150299
Change-Id: If8cdce18a13678ac0646d81bc14850b2f26b6eb7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5367667
Reviewed-by: Noam Rosenthal <[email protected]>
Commit-Queue: Dominic Farolino <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1272720}

--

wpt-commits: e25a0c84dac911c78265c142ab9e178e3936fee2
wpt-pr: 45094
jamienicol pushed a commit to jamienicol/gecko that referenced this pull request Mar 17, 2024
…er execution, a=testonly

Automatic update from web-platform-tests
WPT: Script child removal does not trigger execution

Given the old Chromium change that introduced this behavior:
 - https://source.chromium.org/chromium/chromium/src/+/604e798ec6ee30f44d57a5c4a44ce3dab3a871ed

... the old discussion in:
 - whatwg/dom#732 (review)
 - whatwg/html#4354 (comment)

... and the much newer discussion in:
 - whatwg/dom#1261
 - whatwg/html#10188

This CL upstreams an old test ensuring that removal of a child node
from a script node that has not "already started" [1], does not trigger
script execution. Only the *insertion* of child nodes (to a
non-already-started script node) should trigger that script's execution.

[1]: https://html.spec.whatwg.org/C#already-started

[email protected]

Bug: 40150299
Change-Id: I750ccee0a2be834360c557042e975547c8ddd32c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5367238
Reviewed-by: Noam Rosenthal <[email protected]>
Commit-Queue: Dominic Farolino <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1272330}

--

wpt-commits: cc99c62762135f7e193941e32c3f738960c256be
wpt-pr: 45085
jamienicol pushed a commit to jamienicol/gecko that referenced this pull request Mar 17, 2024
…e WPT expectations, a=testonly

Automatic update from web-platform-tests
DOM: Correct script-in-script atomic move WPT expectations

This CL corrects the script-in-script insertion test, to assert that
when an "outer" script element (that has not yet been prepared/executed)
gets an "inner" script element inserted into it, the outer script runs
before the inner one.

This is a break in what the HTML Standard previously required, before
whatwg/html#10188.

[email protected]

Bug: 40150299
Change-Id: If8cdce18a13678ac0646d81bc14850b2f26b6eb7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5367667
Reviewed-by: Noam Rosenthal <[email protected]>
Commit-Queue: Dominic Farolino <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1272720}

--

wpt-commits: e25a0c84dac911c78265c142ab9e178e3936fee2
wpt-pr: 45094
BruceDai pushed a commit to BruceDai/wpt that referenced this pull request Mar 25, 2024
Given the old Chromium change that introduced this behavior:
 - https://source.chromium.org/chromium/chromium/src/+/604e798ec6ee30f44d57a5c4a44ce3dab3a871ed

... the old discussion in:
 - whatwg/dom#732 (review)
 - whatwg/html#4354 (comment)

... and the much newer discussion in:
 - whatwg/dom#1261
 - whatwg/html#10188

This CL upstreams an old test ensuring that removal of a child node
from a script node that has not "already started" [1], does not trigger
script execution. Only the *insertion* of child nodes (to a
non-already-started script node) should trigger that script's execution.

[1]: https://html.spec.whatwg.org/C#already-started

[email protected]

Bug: 40150299
Change-Id: I750ccee0a2be834360c557042e975547c8ddd32c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5367238
Reviewed-by: Noam Rosenthal <[email protected]>
Commit-Queue: Dominic Farolino <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1272330}
BruceDai pushed a commit to BruceDai/wpt that referenced this pull request Mar 25, 2024
This CL corrects the script-in-script insertion test, to assert that
when an "outer" script element (that has not yet been prepared/executed)
gets an "inner" script element inserted into it, the outer script runs
before the inner one.

This is a break in what the HTML Standard previously required, before
whatwg/html#10188.

[email protected]

Bug: 40150299
Change-Id: If8cdce18a13678ac0646d81bc14850b2f26b6eb7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5367667
Reviewed-by: Noam Rosenthal <[email protected]>
Commit-Queue: Dominic Farolino <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1272720}
source Show resolved Hide resolved
source Show resolved Hide resolved
Copy link
Member

@annevk annevk left a comment

Choose a reason for hiding this comment

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

It would be good if @smaug---- reviewed this as well.

source Show resolved Hide resolved
source Show resolved Hide resolved
source Show resolved Hide resolved
@domfarolino domfarolino requested a review from annevk May 8, 2024 15:31
annevk pushed a commit to whatwg/dom that referenced this pull request Jun 5, 2024
For any given insert operation, these steps run for each inserted node synchronously after all node insertions are complete. This closes #732.

The goal here is to separate the following:

1. Script-observable but not-script-executing insertion side effects
    - This includes synchronously applying styles to the document, etc...
2. Script-executing insertion side effects
    - This includes creating an iframe's document and synchronously firing its load event

For any given call to insert, the above model allows us to keep all of (1) running synchronously after each node's insertion (as part of its insertion steps), while pushing all script-executing (or DOM tree-modifying or frame tree-modifying etc.) side effects to the new set of post-connection steps, which run synchronously during insertion, but _after all_ nodes finish their insertion.

This essentially makes insertions "atomic" from the perspective of script, since script will not run until a given batch of DOM insertions are complete. This two-stage approach aligns the spec with a model most similar to Blink & Gecko's implementation, and fixes #808. This PR also helps out with whatwg/html#1127 and #575 (per #732 (comment)).

To accomplish, this we audited all insertion side effects on the web platform in https://docs.google.com/document/d/1Fu_pgSBziVIBG4MLjorpfkLTpPD6-XI3dTVrx4CZoqY/edit#heading=h.q06t2gg4vpw, and catalogued whether they have script-observable side-effects, whether they invoke script, whether we have tests for them, and how each implementation handles them. This gave us a list of present "insertion steps" that should move to the "post-connection steps", because they invoke script and therefore prevent insertions from being "atomic". This PR is powerless without counterpart changes to HTML, which will actually _use_ the post-connection steps for all current insertion steps that invoke script or modify the frame tree. The follow-up HTML work is tracked here:

- whatwg/html#10188
- whatwg/html#10241
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

None yet

2 participants