[whatwg] Script preloading

Jake Archibald jaffathecake at gmail.com
Wed Jul 10 01:39:53 PDT 2013


On 9 July 2013 20:39, Ian Hickson <ian at hixie.ch> wrote:

> 1. Add a "dependencies" attribute to <script> that can point to other
>    scripts to indicate that execution of this script should be delayed
>    until all other scripts that are (a) earlier in the tree order and (b)
>    identified by this attribute have executed.
>
>      <script id="jquery" src="jquery.js" async></script>
>      <script id="shims" src="shims.js" async></script>
>      <script dependencies="shims jquery" src="myscript.js" async></script>
>
>    This would download jquery.js, shims.js, and myscript.js ASAP, without
>    blocking anything else, and would then run jquery.js and shims.js ASAP,
>    in any order, and then once both have executed, it would execute
>    myscript.js.
>

This works for me can we have it now please?

The "dependencies" attr should make loading non-blocking, even without the
"async" attr. This produces a nice fallback:

<script dependencies id="jquery" src="jquery.js"></script>
<script dependencies id="shims" src="shims.js"></script>
<script dependencies="#shims, #jquery" src="myscript.js"></script>

Browsers without "dependencies" support will load the above in a blocking
way, but at least in a dependable order.

Dependencies should be resolved when the element is inserted into the
document, which avoids circular dependencies.
<script dependencies="#shims" id="jquery" src="jquery.js"></script>
<script dependencies="#jquery" id="shims" src="shims.js"></script>
The first script above would have no dependencies and will execute as soon
as it downloads, as there was no element with ID "shims" when dependencies
were resolved.

Also, as above, it'd be great if "dependencies" took CSS selectors rather
than IDs, this means:
<script dependencies="script" id="shims" src="shims.js"></script>
becomes the declarative form of async=false.

The CMS plugins from Kyle's example would use dependencies="script" until
they become more script-aware.

The "dependencies" attribute should also work on scripts without "src", eg
<script dependencies id="jquery" src="jquery.js"></script>
<script dependencies="#jquery">
  // jquery is ready
</script>


> 2. Add an "whenneeded" boolean content attribute, a "markNeeded()" method,
>    and an internal "is-needed flag" (initially false) to the <script>
>    element. When a script is about to execute, if its whenneeded=""
>    attribute is set, but its "is-needed" flag is not, then delay
>    execution. Calling markNeeded() on a script that has a whenneeded
>    boolean but that has not executed yet first causes the markNeeded()
>    method on all the script's dependencies to be called, and then causes
>    this script to become ready to execute.
>
>      <script id="jquery" src="jquery.js" async whenneeded></script>
>      <script id="shims" src="shims.js" async whenneeded></script>
>      <script id="myscript" dependencies="shims jquery" src="myscript.js"
>              async whenneeded></script>
>
>    This would download jquery.js, shims.js, and myscript.js ASAP, and then
>    wait for further instructions.
>
>      document.getElementById('myscript').markNeeded();
>
>    This would then cause the scripts to execute, first jquery.js and
>    shims.js (in any order), and then myscript.js. If any hadn't finished
>    downloading yet, it would first wait for that to finish.
>
>    (We could make markNeeded() return a promise, too.)
>

I'm similarly not-convinced on delayed parsing/execution. This is better
solved by moving parsing onto a different thread, then the whole web
benefits rather than just those using this new feature. I'm open to
evidence to the contrary.

I've delayed/avoided parsing to great performance benefit on ancient
devices, but this feature won't be adopted there. In this edge-case, hacks
such as HTML comments are best and supported today.

However, if this feature were adopted, "dependencies" would be redundant,
as I could do it all myself with markNeeded().

<script id="jquery" src="jquery.js" whenneeded></script>
<script id="shims" src="shims.js" whenneeded></script>
<script id="myscript" src="myscript.js" whenneeded></script>
<script>
  Promise.every(
    document.querySelector('#jquery').markNeeded(),
    document.querySelector('#shims').markNeeded()
  ).then(function() {
    document.querySelector('#myscript').markNeeded()
  });
</script>


> Is there a need for delaying the download of a script as well? (If so, we
> could change whenneeded="" to have values, like whenneeded="execute" vs
> whenneeded="download" or something.)
>

I don't have a use-case for this that isn't handled by dynamic script
insertion.


> Is there something this doesn't handle which it would need to handle?
>

The "dependencies" attribute, along with the CSS selector stuff,
'async'-like behaviour by default & if it's allowed on inline scripts meets
all my use-cases.

For completeness, here are my requirements:

   - Does not block page rendering
   - Provides an adoption path for browsers that don't support the new
   feature (happy for the fallback to be blocking document-order execution)
   - Allows scripts to execute in any order as along as their dependencies
   are met (so async=false is not enough)
   - Is discoverable by pre-parsers (so async=false and old-IE's readystate
   methods aren't enough)

Jake.



More information about the whatwg mailing list