-
Notifications
You must be signed in to change notification settings - Fork 295
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
Side effects due to tree insertion or removal (script, iframe) #808
Comments
@emilio has thought about this some as well, I think. |
Gecko has a slightly different (and somewhat weird) model for Gecko loads iframes from the outermost call |
As noted by @nox |
@mfreed7 @tkent-google @rniwa @cdumez ping. |
(I delegate to @mfreed7. I'm not responsible for HTML any longer.) |
In WebKit, insertion and removal are different. Newly inserted nodes are notified in two stages: During removal, we disconnect all subframes first (during which introduction of nested browsing contexts are prohibited) and then remove nodes but we don't allow any scripts to execute as a result of removing nodes once we start removing nodes. All of this happens synchronously. |
By some kind of queue, do you mean that they need to fire events and run script asynchronously by posting a task instead of synchronously? I wasn't familiar with mutation events before this and I'm still not super familiar with mutation observer - are mutation events synchronous and is mutation observer async?
By this model, do you mean they do sync as opposed to async? Should script tags have their script executed async to when they are appended? |
No, insertion/removal runs "synchronous callbacks" for multiple elements. After those callbacks, we run another set of "synchronous callbacks" to execute script for impacted elements. There's no tasks involved. Queue is a reference to https://infra.spec.whatwg.org/#queue (a type of list). |
Is the goal here simply to remove mutation events? Based on tkent's doc I found in #305, it sounds like we would already have to contact sites to get them to stop using mutation events in order to change their behavior - why not skip the change in behavior and just get rid of them altogether in one step?
Are there any examples which would help me understand how these operations run script? Is it all just mutation events or is it something else? |
None of that is related to mutation events. |
Thanks for listing these examples!
Are there any other side effects of interest, or is that it? For the script and unload cases, is the goal really to make script get executed after insertion and make unload fire after remove? I don't really see the benefit and I feel like we would just be breaking websites, especially since the behavior is already the same in chrome firefox and safari. For the sync load event case, I suppose it is worth looking into changing in chrome, although I think this could be very challenging to implement and I'm afraid of breaking websites. Does anyone know if there is already a crbug open for this? |
That is one of the open questions, yes.
I believe the intent is to define exactly when during the insertion or removal the side effects happen. For example, if you insert a subtree into the DOM that contains two
Please see whatwg/html#4965 for previous discussion on that topic. Your fears are not unjustified, but we still need to figure out how to spec something that is web-compatible (the current spec is not, afaict) and then get everyone to converge on that behavior. And again, if the behavior here ends up "sync load event", then you have to define exactly when it fires. Again, consider inserting a subtree with several iframes and script tags in it; the precise order of all the script executions and the DOM state they see needs to be defined. Including in the face of the executions further mutating the DOM. |
Would it be possible to defer removal side effects until the next style/layout update (typically the next rendering update). This would align nicely with |
|
I've discussed this a bit with Tab and at length with Anne and I've tried to compile and synthetize the UA behaviors in various scenarios. I'm posting this before I submit the report on the current state of UAs (base on Anne's work chasing down inconsistencies), to make sure:
TimelineGiven a composite DOM operation (adding a fragment with several children, or setting
There are several tightly async queues (both before and after). We'll say that queues that are closer in time to DOM tree manipulations are tighter. The terminology here probably isn't optimal, because one might be tempted to say that a queue that is less tight is looser, perhaps seeding confusion... Maybe we can agree on avoiding "loose" in these conversations, and use "less tight" instead. Timeline boundariesAnother useful concept re sync vs async would be timeline boundaries: el.append(fragment)
[ // control passes to the browser
[ /* mutation events queue */ ]
[ /* tree operations */ ]
[ /* custom element hooks queue */ ]
] //control returned to the calling code Where the queues are async relative to DOM tree manipulations, but within the sync bounds of Effect typologyI've also tried to categorize the nature of the effects we deal with that are either synchronous or tightly async, at least in some UAs:
AFAICT 2.x operations don't trigger JS because they either mutate internal slots, or operate on objects that are locked and can't be spied upon using setters. I've only investigated this from JS, which makes it impossible to determine whether 2.x effects are synchronous or tightly async, with queues tighter than the JS ones. It shouldn't matter as far as WebCompat or specs are concerned, since these details are not user visible. I may refer to these as "synchronous 2.x" for convenience. Going forwardProvided that the UAs have different behavior, it is unlikely that user code in production relies on their timelines and this gives us leeway to reorder things. It would seem ideal to
edit: added the bit about timeline boundaries |
Yeah agreed. While we need to define state changes, their relative order is only important to the extent that it is observable through JavaScript. And I personally think it would be great if JavaScript could be deferred as much as possible to the end, but mutation events are a major gotcha there. As I believe there is still some ambition to remove or change the timing of mutation events, I'm not sure we want to include them as part of this work. That would increase the complexity quite a bit. |
I've noticed two pre-DOM queues: one for the The latter intermixes JS callbacks and state changes (each If they can't be moved post-DOM for Web compat reasons, a possible mitigation would be, when DOM operations are triggered from JS, to register every node involved in a Set, and to prevent as many mutations as possible on these nodes from the pre-DOM hooks by throwing errors. This would move us closer to transactional behavior. I suppose the list of operations that can be safely prohibited could be determined thanks to telemetry. |
It surprised me to read this. It's possible things in the spec have seriously changed for the better in the intervening years, but I always understood HTML/DOM to be pretty explicit about when insertion/removal side-effects happen. For example, DOM defines the insertion steps hook, which HTML overrides. Furthermore, HTML provides a per-element HTML element insertion steps hook that runs during HTML's own "insertion steps" for any element that overrides said hook. HTML also provides more granular hooks for acting on the narrow case when an element is "inserted into a document", and the wider/general case of when an element "becomes connected". These hooks should pretty clearly define the ordering of insertion/removal side-effects, especially for simple elements that don't do a lot during these hooks. But even for complicated cases like in the OP, or with multiple iframe removals (as @annevk mentioned), I think the spec is at least clear on what it calls for. Removing multiple iframesFrom #808 (comment):
I think the spec is clear on this, if for no other reason than in the intervening years the navigation and session history rewrite has landed, and follow-ups like whatwg/html#9907 have made things even better. If you have a document with two sibling iframes, and a script that calls
The spec is equally clear for cases with nested iframes and so on, as calls to the "removing steps" are properly recursive. So spec-wise, I don't think there should be a way to observe the "intermediate state" at all when all removes happen synchronously with respect to each other. However, implementations seem to all disagree with the spec in the same way! Chrome, Firefox, Safari This is kinda weird, but I don't think it's "broken", and FWIW all browsers are dead consistent. Here's what they can observe in the unload handler "mid-removal":
But this Inserted DocumentFragment with two scriptsConsider the example in the OP. This is the flow the spec follows (again, bold is where (queued) scripts will run):
Only Safari follows the spec, and Chrome and Firefox behave exactly how the OP describes. So there is a clear interop issue, but the standard at least makes it clear which implementation is right vs. wrong. The question is: is the spec + Safari being aligned sufficient to simply call these "Chrome and Firefox bugs," or do we want to adjust the standard? I think the spec + Safari behavior is closer to what we all want, so maybe we can just file some Chrome + Firefox bugs, but I'd love to know what @annevk thinks. |
I think what I dislike about the current model is that insertion is not atomic from the perspective of script. If it works for everyone though we should add the various scenarios mentioned here and related issues to WPT and call it a day. |
Can you clarify exactly what you mean? Outside of a few implementation bugs mentioned above, it seems the spec is pretty clear that insertion/removal should be atomic from the perspective of script, since I don't think any overridden insertion / removal steps synchronously invoke script, right? Edit: One obvious exception I guess would be iframe insertion, which very explicitly fires the
Regardless, yes I agree, I'll get a PR up for adding these scenarios as WPTs and continue the discussion here if anything interesting arises. |
To help resolve whatwg/dom#808, we need WPTs asserting exactly when (DOM-observing) script can and cannot be invoked during the insertion and removing steps for iframes. [email protected] Bug: N/A Change-Id: Iff959bbb0d32d772ae7162d5d9e54a5817959086
@domfarolino I mean that the insert operation hasn't completed by the time script executes (there's still another script to insert). From that perspective I like the staging that I think Gecko has. Whereby you complete insertion and then have another loop/queue for side effects. |
I don't remember if I ever followed up on this (health issues make me not as reliable as I'd like), but I remember finding many observable discrepancies in the way insertion and removal work last year. Unless it has been homogenized in the mean time, there was room for straightening the timing in a way that seemed Web compatible. I'll try to look for what I had found and re-check anyway. |
To help resolve whatwg/dom#808, we need WPTs asserting exactly when (DOM-observing) script can and cannot be invoked during the insertion and removing steps for iframes. [email protected] Bug: N/A Change-Id: Iff959bbb0d32d772ae7162d5d9e54a5817959086
I see. So you would like multiple, synchronously back-to-back insertions (of say, several
I have two comments on this. First, I think Gecko's model is fairly desirable, however I think Chrome's is slightly more consistent. Both are pretty much (2) above. Both implementations execute scripts after all have been appended to the DOM (so that earlier scripts can observe later scripts and remove them from the DOM). However Chromium refuses to execute a script that an earlier script removed from the DOM, which I think is consistent with our general policy of not executing scripts that have changed documents (whatwg/html#5575). Second, if we think (2) above is desirable, do we think we can actually change the spec + Safari to align on all of this? For |
To help resolve whatwg/dom#808, we need WPTs asserting exactly when (DOM-observing) script can and cannot be invoked during the insertion and removing steps for iframes and script elements. The tests in this CL assert the current spec behavior of: Iframe: - Insertion: - Synchronously fire the `load` event in the iframe document - Removal: - No script is run in between multiple iframe removals. Script cannot observe the state of the DOM in between multiple synchronous removals because, i.e., no `unload` events are fired in this case per HTML [1]. Script: - Insertion: - Synchronously execute <script> elements upon insertion, even in between the insertions of individual <script> elements that are added "atomically" by a single DocumentFragment insertion. Note that Chromium and Gecko fail this test. In the DocumentFragment case, both of these browsers insert all <scripts> into the DOM before executing any of them. This means that once the scripts start executing, they can all observe each other's participation in the DOM tree. At the moment, there is ongoing discussion [2] about the possibility of changing the DOM/HTML Standard's model to more-closely match what Gecko and Chromium do with "atomic" DOM insertion (i.e., running script as a side effect very explicitly after all DOM node insertion is done). [1]: https://html.spec.whatwg.org/C#the-iframe-element:html-element-removing-steps [2]: whatwg/dom#808 (comment) [email protected] Bug: N/A Change-Id: Iff959bbb0d32d772ae7162d5d9e54a5817959086
Thank you for the In any event, what we end up with has to be consistent. You cannot have some script execution be delayed, but still be able to do script execution with some other element. Consistency trumps any desire for atomic insert operations. (Atomicity per task can't really work by the way. Scripts already execute way sooner than that.) |
Yep you are correct, the @noamr has kindly helped shape up web-platform-tests/wpt#15264 into the new web-platform-tests/wpt#44658 for tentative tests around the model proposed here. We're planning on landing that alongside web-platform-tests/wpt#44308, and we'll be simultaneously reviving #732 (which you also pointed me to) to try and finish this off. Note that regarding removal, I don't think we an have the same kind of "atomicity" that we're shooting for with insertion. In the insertion case, we can defer some actions until after DOM mutations because the element is supposed to be connected at that point. Removals work differently because the removal steps run before each node actually gets removed from the DOM / disconnected. Moving the steps after all DOM mutations (for removals) would mean executing steps on disconnected nodes, which sounds like a bad idea (and the cause for many security bugs it sounds). So I think that preserving the asymmetry between insertion and removal is OK. Let me know if you think otherwise. |
To help resolve whatwg/dom#808, we need WPTs asserting exactly when (DOM-observing) script can and cannot be invoked during the insertion and removing steps for iframes and script elements. The tests in this CL assert the current spec behavior of: Iframe: - Insertion: - Synchronously fire the `load` event in the iframe document - Removal: - No script is run in between multiple iframe removals. Script cannot observe the state of the DOM in between multiple synchronous removals because, i.e., no `unload` events are fired in this case per HTML [1]. Script: - Insertion: - Synchronously execute <script> elements upon insertion, even in between the insertions of individual <script> elements that are added "atomically" by a single DocumentFragment insertion. Note that Chromium and Gecko fail this test. In the DocumentFragment case, both of these browsers insert all <scripts> into the DOM before executing any of them. This means that once the scripts start executing, they can all observe each other's participation in the DOM tree. At the moment, there is ongoing discussion [2] about the possibility of changing the DOM/HTML Standard's model to more-closely match what Gecko and Chromium do with "atomic" DOM insertion (i.e., running script as a side effect very explicitly after all DOM node insertion is done). [1]: https://html.spec.whatwg.org/C#the-iframe-element:html-element-removing-steps [2]: whatwg/dom#808 (comment) [email protected] Bug: 40150299 Change-Id: Iff959bbb0d32d772ae7162d5d9e54a5817959086
To help resolve whatwg/dom#808, we need WPTs asserting exactly when (DOM-observing) script can and cannot be invoked during the insertion and removing steps for iframes and script elements. The tests in this CL assert the current spec behavior of: Iframe: - Insertion: - Synchronously fire the `load` event in the iframe document - Removal: - No script is run in between multiple iframe removals. Script cannot observe the state of the DOM in between multiple synchronous removals because, i.e., no `unload` events are fired in this case per HTML [1]. Script: - Insertion: - Synchronously execute <script> elements upon insertion, even in between the insertions of individual <script> elements that are added "atomically" by a single DocumentFragment insertion. Note that Chromium and Gecko fail this test. In the DocumentFragment case, both of these browsers insert all <scripts> into the DOM before executing any of them. This means that once the scripts start executing, they can all observe each other's participation in the DOM tree. At the moment, there is ongoing discussion [2] about the possibility of changing the DOM/HTML Standard's model to more-closely match what Gecko and Chromium do with "atomic" DOM insertion (i.e., running script as a side effect very explicitly after all DOM node insertion is done). [1]: https://html.spec.whatwg.org/C#the-iframe-element:html-element-removing-steps [2]: whatwg/dom#808 (comment) [email protected] Bug: 40150299 Change-Id: Iff959bbb0d32d772ae7162d5d9e54a5817959086
To help resolve whatwg/dom#808, we need WPTs asserting exactly when (DOM-observing) script can and cannot be invoked during the insertion and removing steps for iframes and script elements. The tests in this CL assert the current spec behavior of: Iframe: - Insertion: - Synchronously fire the `load` event in the iframe document - Removal: - No script is run in between multiple iframe removals. Script cannot observe the state of the DOM in between multiple synchronous removals because, i.e., no `unload` events are fired in this case per HTML [1]. Script: - Insertion: - Synchronously execute <script> elements upon insertion, even in between the insertions of individual <script> elements that are added "atomically" by a single DocumentFragment insertion. Note that Chromium and Gecko fail this test. In the DocumentFragment case, both of these browsers insert all <scripts> into the DOM before executing any of them. This means that once the scripts start executing, they can all observe each other's participation in the DOM tree. At the moment, there is ongoing discussion [2] about the possibility of changing the DOM/HTML Standard's model to more-closely match what Gecko and Chromium do with "atomic" DOM insertion (i.e., running script as a side effect very explicitly after all DOM node insertion is done). [1]: https://html.spec.whatwg.org/C#the-iframe-element:html-element-removing-steps [2]: whatwg/dom#808 (comment) [email protected] Bug: 40150299 Change-Id: Iff959bbb0d32d772ae7162d5d9e54a5817959086 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5251828 Reviewed-by: Mason Freed <[email protected]> Commit-Queue: Dominic Farolino <[email protected]> Cr-Commit-Position: refs/heads/main@{#1264406}
To help resolve whatwg/dom#808, we need WPTs asserting exactly when (DOM-observing) script can and cannot be invoked during the insertion and removing steps for iframes and script elements. The tests in this CL assert the current spec behavior of: Iframe: - Insertion: - Synchronously fire the `load` event in the iframe document - Removal: - No script is run in between multiple iframe removals. Script cannot observe the state of the DOM in between multiple synchronous removals because, i.e., no `unload` events are fired in this case per HTML [1]. Script: - Insertion: - Synchronously execute <script> elements upon insertion, even in between the insertions of individual <script> elements that are added "atomically" by a single DocumentFragment insertion. Note that Chromium and Gecko fail this test. In the DocumentFragment case, both of these browsers insert all <scripts> into the DOM before executing any of them. This means that once the scripts start executing, they can all observe each other's participation in the DOM tree. At the moment, there is ongoing discussion [2] about the possibility of changing the DOM/HTML Standard's model to more-closely match what Gecko and Chromium do with "atomic" DOM insertion (i.e., running script as a side effect very explicitly after all DOM node insertion is done). [1]: https://html.spec.whatwg.org/C#the-iframe-element:html-element-removing-steps [2]: whatwg/dom#808 (comment) [email protected] Bug: 40150299 Change-Id: Iff959bbb0d32d772ae7162d5d9e54a5817959086 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5251828 Reviewed-by: Mason Freed <[email protected]> Commit-Queue: Dominic Farolino <[email protected]> Cr-Commit-Position: refs/heads/main@{#1264406}
…s WPTs, a=testonly Automatic update from web-platform-tests DOM: Add iframe insertion & removal steps WPTs To help resolve whatwg/dom#808, we need WPTs asserting exactly when (DOM-observing) script can and cannot be invoked during the insertion and removing steps for iframes and script elements. The tests in this CL assert the current spec behavior of: Iframe: - Insertion: - Synchronously fire the `load` event in the iframe document - Removal: - No script is run in between multiple iframe removals. Script cannot observe the state of the DOM in between multiple synchronous removals because, i.e., no `unload` events are fired in this case per HTML [1]. Script: - Insertion: - Synchronously execute <script> elements upon insertion, even in between the insertions of individual <script> elements that are added "atomically" by a single DocumentFragment insertion. Note that Chromium and Gecko fail this test. In the DocumentFragment case, both of these browsers insert all <scripts> into the DOM before executing any of them. This means that once the scripts start executing, they can all observe each other's participation in the DOM tree. At the moment, there is ongoing discussion [2] about the possibility of changing the DOM/HTML Standard's model to more-closely match what Gecko and Chromium do with "atomic" DOM insertion (i.e., running script as a side effect very explicitly after all DOM node insertion is done). [1]: https://html.spec.whatwg.org/C#the-iframe-element:html-element-removing-steps [2]: whatwg/dom#808 (comment) [email protected] Bug: 40150299 Change-Id: Iff959bbb0d32d772ae7162d5d9e54a5817959086 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5251828 Reviewed-by: Mason Freed <[email protected]> Commit-Queue: Dominic Farolino <[email protected]> Cr-Commit-Position: refs/heads/main@{#1264406} -- wpt-commits: 2a023b35ecade9e3370800b430818c75af1819cb wpt-pr: 44308
…s WPTs, a=testonly Automatic update from web-platform-tests DOM: Add iframe insertion & removal steps WPTs To help resolve whatwg/dom#808, we need WPTs asserting exactly when (DOM-observing) script can and cannot be invoked during the insertion and removing steps for iframes and script elements. The tests in this CL assert the current spec behavior of: Iframe: - Insertion: - Synchronously fire the `load` event in the iframe document - Removal: - No script is run in between multiple iframe removals. Script cannot observe the state of the DOM in between multiple synchronous removals because, i.e., no `unload` events are fired in this case per HTML [1]. Script: - Insertion: - Synchronously execute <script> elements upon insertion, even in between the insertions of individual <script> elements that are added "atomically" by a single DocumentFragment insertion. Note that Chromium and Gecko fail this test. In the DocumentFragment case, both of these browsers insert all <scripts> into the DOM before executing any of them. This means that once the scripts start executing, they can all observe each other's participation in the DOM tree. At the moment, there is ongoing discussion [2] about the possibility of changing the DOM/HTML Standard's model to more-closely match what Gecko and Chromium do with "atomic" DOM insertion (i.e., running script as a side effect very explicitly after all DOM node insertion is done). [1]: https://html.spec.whatwg.org/C#the-iframe-element:html-element-removing-steps [2]: whatwg/dom#808 (comment) [email protected] Bug: 40150299 Change-Id: Iff959bbb0d32d772ae7162d5d9e54a5817959086 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5251828 Reviewed-by: Mason Freed <[email protected]> Commit-Queue: Dominic Farolino <[email protected]> Cr-Commit-Position: refs/heads/main@{#1264406} -- wpt-commits: 2a023b35ecade9e3370800b430818c75af1819cb wpt-pr: 44308
Seems this was prematurely closed? |
Yeah, don't write "resolve" followed by a link to an issue in your commit message if they don't actually resolve it. (It was initially not a problem as the bot doesn't have access to this repository, but some other people including rniwa do.) |
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
For any given insert operation, these steps run for each inserted node synchronously after all node insertions are complete. This closes whatwg#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 whatwg#808. This PR also helps out with whatwg/html#1127 and whatwg#575 (per whatwg#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
Use the newly-introduced DOM Standard "post-connection steps" (see whatwg/dom@0616094), 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. Before this, 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 Gecko. We push script execution back to the post-connection steps, which run after all DOM insertions are complete. This gives two notable observable differences: 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, doing script.append(new Text("..."), new Text("..."), ...) would "prepare" and "execute" the script synchronously after the first text node was inserted, because previously any child node insertion would cause script preparation. With this change, 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. 2. The post-connection 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-connection steps") after the parent script gets a chance at running (as a result of its "children changed steps", which run before any post-connection steps). The new spec text has an example of this. This PR supersedes a portion of #4354.
Use the newly-introduced DOM Standard "post-connection steps" (see whatwg/dom@0616094), 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. Before this, 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 Gecko. We push script execution back to the post-connection steps, which run after all DOM insertions are complete. This gives two notable observable differences: 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, doing script.append(new Text("..."), new Text("..."), ...) would "prepare" and "execute" the script synchronously after the first text node was inserted, because previously any child node insertion would cause script preparation. With this change, 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. 2. The post-connection 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-connection steps") after the parent script gets a chance at running (as a result of its "children changed steps", which run before any post-connection steps). The new spec text has an example of this. This PR supersedes a portion of whatwg#4354.
Elements that trigger a script-executing side effect due to insertion or removal need to do so using some kind of queue if we ever want to remove mutation events fully (see #305). In particular, I think it's important that tree mutation succeeds and that any script is executed afterwards (but before custom element reactions, see web-platform-tests/wpt#20660).
I'd like to use this thread for discussion, since currently it's spread among various places (#575, #732, whatwg/html#4354, whatwg/html#4611, whatwg/html#4965).
Chrome and Firefox have this model for
script
insertion. (Though there are differences, if two scripts are inserted and the first removes the second, Firefox will execute the second, Chrome will not. They also react differently to changes to children of the script element, with Chrome only caring about insertions there.)Chrome has this model for
iframe
insertion as well, but not removal. Firefox only has it for removal (insertion cannot trigger script in Firefox as it does not have a synchronousload
event; note that this means that Chrome and Firefox create nested browsing contexts at different times).Firefox has this model for
style
insertion, but sincestyle
cannot trigger script I don't think we should follow that.@nox @bzbarsky @tkent-google @rniwa thoughts? Do we all share the overall goal of executing script at a "safe" point? How would you like to see this broken down further?
The text was updated successfully, but these errors were encountered: