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

Clean up the script element processing model #7876

Merged
merged 25 commits into from
May 19, 2022
Merged

Conversation

domenic
Copy link
Member

@domenic domenic commented Apr 29, 2022

  • Modernize the definitions and usage of various fields associated with script element, e.g. by removing "scare quotes", changing names from verbose things like "the script's type" to just "type", changing flags to booleans, ensuring initial values are defined, etc. Notable field changes:
    • Rename "the script's type" to "result". This serves as preparation for other specifications, such as import maps, which will expand what that field can contain.
    • Invert "non-blocking" into "blocking" to avoid double-negatives.
  • Revamp "the script is ready" into three separate concepts: "delaying the load event", "mark as ready", and "list of steps to run when the result is ready". Fixes "the script is ready" doesn't really work #5217, in particular making it so that script elements which are never marked as ready (e.g., <script type="foobar">) don't delay the load event indefinitely.
  • Un-export "prepare a script". All uses of it in external specs are either monkeypatches or non-normative references.
  • Rename "prepare a script" to "prepare the script element" to emphasize it's about the <script> element, not about the separate script concept.
  • Rename "execute a script block" to "execute the script element", since "block" is a strange term.
  • Various other editorial improvements to those two algorithms.

This is probably best reviewed commit-by-commit. Everything is intended to be editorial except for the fix for #5217 which happened by accident.

I mainly did this as preparation for future script element integrations like import maps.

/cc @hiroshige-g as FYI


/parsing.html ( diff )
/scripting.html ( diff )
/xhtml.html ( diff )

@domenic domenic requested a review from annevk May 3, 2022 22:06
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.

This largely looks correct to me, but I did spot some weirdness. If @hiroshige-g has the time to read through it as well I think that would be good.

Are you planning on landing this as independent commits? Should they be prefixed with Editorial:?

source Show resolved Hide resolved
source Show resolved Hide resolved
source Show resolved Hide resolved
source Outdated Show resolved Hide resolved
@domenic
Copy link
Member Author

domenic commented May 6, 2022

Are you planning on landing this as independent commits? Should they be prefixed with Editorial:?

I was planning to land this as one large commit, with the description given in the PR. It's just separate commits for easier review.

source Show resolved Hide resolved
source Show resolved Hide resolved
@hiroshige-g
Copy link
Contributor

Invert "non-blocking" into "blocking" to avoid double-negatives.

I feel other kinds of names would be better, because this flag is not a simple "non-blocking" flag, and having "blocking", "parser-blocking", and "render-blocking" might be confusing.
e.g. "non-blocking" => "force-async" (not so sure though)? as this flag (when true) makes async IDL attribute true even if async content attribute doesn't exist, and makes the script async.

@domenic
Copy link
Member Author

domenic commented May 6, 2022

Yeah I agree the blocking name could be better. If you or someone else can come up with a good alternative I'll happily use that instead. Force-async might indeed be good, I'll have to re-read through the usage sites to make sure.

@annevk
Copy link
Member

annevk commented May 9, 2022

I don't understand how the non-blocking/blocking thing functions. Where it currently unsets non-blocking it notes:

This ensures that, if the script is external, any document.write() calls in the script will execute in-line, instead of blowing the document away, as would happen in most other cases. It also prevents the script from executing until the end tag is seen.

However, deep down in "prepare a script" for the matching condition (where non-blocking is unset) it says

Add the element to the end of the list of scripts that will execute in order as soon as possible associated with the element's preparation-time document.

Which doesn't guarantee execution upon seeing the </script> tag at all as far as I can tell. I thought this would force the script to be parser-blocking, but now I don't know.

@hiroshige-g
Copy link
Contributor

I interpret the comment is about "Set the element's parser document to the Document", not the non-blocking flag.

The non-blocking flag seems to make dynamically inserted <script> just after creation async, even though it doesn't have async content attribute.

It might be easier to understand if we rewrite Step 28 of prepare-a-script like:

  • If (the script's type is "classic" and the element has a src attribute), or the script's type is "module":
    • If the element has an async attribute, or the element has the "non-blocking" flag set:
      • => async (set of scripts that will execute as soon as possible)
    • Else if the element is not "parser-inserted":
      • => in order (list of scripts that will execute in order as soon as possible)
    • Else if the element has a defer attribute, or the script's type is "module":
      • => defer (list of scripts that will execute when the document has finished parsing)
    • Else:
  • Else:
    • If the element is "parser-inserted", and either the parser that ...
      • => parser-blocking
    • Else:
      • => Immediate evaluation

https://docs.google.com/presentation/d/1aw4zIJKgqtmeja5poJCG1jLBM5H7PyWlgrgk8iEiayM/edit#slide=id.g8621aafc1b_0_73

@annevk
Copy link
Member

annevk commented May 13, 2022

While trying to figure out what a good name would be, I found an interesting difference between browsers:

<script type=x></script>
<script>
console.log(document.querySelector("script").async)
</script>

(Chrome/Safari appear compliant with true.)

"Async fallback" might be another good name for this state as we use this when the async content attribute is absent.

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.

@hiroshige-g's comments still need to be addressed, but I figured I'd approve this from an editorial perspective.

@domenic
Copy link
Member Author

domenic commented May 16, 2022

OK, I think this is ready. Another review from @hiroshige-g would be appreciated before merging. The major changes are blocking => force async (and flipping the boolean back), and incorporating Hiroshige's rewrite of step 28. Both seemed to improve clarity quite a lot.

source Outdated Show resolved Hide resolved
source Show resolved Hide resolved
source Show resolved Hide resolved
source Show resolved Hide resolved
source Show resolved Hide resolved
source Show resolved Hide resolved
source Show resolved Hide resolved
<p>Add the element to the end of the <dfn>list of scripts that will execute when the document
has finished parsing</dfn> associated with the element's <span>parser document</span>.</p>
<ol>
<li id="script-processing-src">
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: this id assignments look weird, but I don't have better ideas to keep the historical IDs (yeah, looks very historical) to work.

<p>Each <code>Document</code> has a <dfn>pending parsing-blocking script</dfn>, which is a
<code>script</code> element or null, initially null.</p>

<p>Each <code>Document</code> has a <dfn>set of scripts that will execute as soon as
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be easier to understand and more self-documented for future spec readers if we rename these to e.g.

  • set of async scripts
  • list of in-order scripts (I'm not sure what is the name for this -- I searched "async = false" and didn't find articles explicit names for this case. "in-order" is a word I used in Chromium implementation, but I'm not sure this is natural for e.g. web developers)
  • list of defer scripts

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 am not 100% sure on this. I kind of like how the current names describe behavior, instead of relying on knowing what async or defer means.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm also not so confident. Then let's leave them as-is.

@hiroshige-g
Copy link
Contributor

LGTM!

@domenic domenic merged commit b83a82f into main May 19, 2022
@domenic domenic deleted the script-fields-cleanup branch May 19, 2022 22:02
aarongable pushed a commit to chromium/chromium that referenced this pull request Aug 3, 2022
In order to

- Reflect HTML spec updates, mainly
  whatwg/html#7876, and
- Make the intervention logic clearer.

Namely, this CL largely refactors the final part of
`PrepareScript()` (corresponding to Steps 31 and 32),
by changing the code structure according to html#7876
and restructuring the logic into three steps:

1. Determine per-spec scheduling type in
   `GetScriptSchedulingTypePerSpec()`.
2. Modify the scheduling type due to interventions, and
3. Actually schedule scripts based on the scheduling type
   and interact with ScriptRunner and parsers.

Other parts are more straightforward and somehow mechanical:

- Renaming ScriptLoader::`non_blocking_` to `force_async_`.
- Updating spec comments (using
  https://docs.google.com/document/d/1vmnpbDvMR-ph0v88lC810xsE6kjWVsQP351_l65pxLs/edit#heading=h.2obuaw96wltr).
- Other very minor refactoring.

This CL shouldn't change the behavior.

Bug: 1344772, 1340837, 1339112
Change-Id: I788f682531fa0d417338562a4f0420f4c8b49e72
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3795585
Reviewed-by: Kouhei Ueno <kouhei@chromium.org>
Reviewed-by: Minoru Chikamune <chikamune@chromium.org>
Reviewed-by: Shunya Shishido <sisidovski@chromium.org>
Commit-Queue: Hiroshige Hayashizaki <hiroshige@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1031114}
mjfroman pushed a commit to mjfroman/moz-libwebrtc-third-party that referenced this pull request Oct 14, 2022
In order to

- Reflect HTML spec updates, mainly
  whatwg/html#7876, and
- Make the intervention logic clearer.

Namely, this CL largely refactors the final part of
`PrepareScript()` (corresponding to Steps 31 and 32),
by changing the code structure according to html#7876
and restructuring the logic into three steps:

1. Determine per-spec scheduling type in
   `GetScriptSchedulingTypePerSpec()`.
2. Modify the scheduling type due to interventions, and
3. Actually schedule scripts based on the scheduling type
   and interact with ScriptRunner and parsers.

Other parts are more straightforward and somehow mechanical:

- Renaming ScriptLoader::`non_blocking_` to `force_async_`.
- Updating spec comments (using
  https://docs.google.com/document/d/1vmnpbDvMR-ph0v88lC810xsE6kjWVsQP351_l65pxLs/edit#heading=h.2obuaw96wltr).
- Other very minor refactoring.

This CL shouldn't change the behavior.

Bug: 1344772, 1340837, 1339112
Change-Id: I788f682531fa0d417338562a4f0420f4c8b49e72
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3795585
Reviewed-by: Kouhei Ueno <kouhei@chromium.org>
Reviewed-by: Minoru Chikamune <chikamune@chromium.org>
Reviewed-by: Shunya Shishido <sisidovski@chromium.org>
Commit-Queue: Hiroshige Hayashizaki <hiroshige@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1031114}
NOKEYCHECK=True
GitOrigin-RevId: d2415ae4482085c4909f5cce94de255491a7f5da
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.

"the script is ready" doesn't really work
3 participants