[whatwg] Script preloading

Jake Archibald jaffathecake at gmail.com
Wed Jul 10 09:37:34 PDT 2013


On 10 July 2013 16:39, Kyle Simpson <getify at gmail.com> wrote:

> > The IE4-10 technique is invisible to pre-parsers, if we're chasing
> performance here it's not good enough.
> > ...
> > Also invisible to preloaders.
>
> I personally don't care about scripts being discoverable by pre-parsers. I
> have done testing and am not convinced that something appearing earlier (in
> markup) leads to better performance than allowing my script loading logic
> to load things when I want, and just relying on the browser to do that as
> quickly as possible.
>

Pre-parsers can kick in before a page is actually opened, but script cannot
be executed. Let me dig up some numbers on the benefits of this & report
back. But logically, [parse html]->[load script] is always going to be
faster than [parse html]->[parse inline script]->[execute inline
script]->[load script]. And I imagine, more bytes and complex.


> It's quite possible that this is because when I use script loading,
> generally speaking, I'm only loading the scripts I consider to be most
> critical for actual page load (not everything and the kitchen sink), so my
> script-based script loading during page-load usually is pretty darn quick.
> I "defer" the rest of my code that's not as critical until later (perhaps
> until when needed, strictly), which is something that markup alone doesn't
> let me do.
>

If it's something likely to be used later you're better off loading it with
the page. Waking up the radio on a mobile connection is slow and uses
battery. Having said that, there's nothing in either of the original
proposals that prevents adding scripts dynamically. It's the more complex
option if you want more complex behaviour.


> The fact that browsers are trying to second guess developers and
> look-ahead to find and prioritize certain resources is NOT something I
> consider a positive benefit that I'm eager to assist. I still come from a
> world where a developer ought to get to decide what's higher priority.
>

Browsers already do this to proven benefit, but download priority is
outside the scope of this discussion.


> There's certainly a strong pre-disposition among a lot of developers to
> falling in love with declarative markup-only solutions. I share no such
> obsession, when it comes to script loading. I think script loading is far
> more complex than markup is ever going to be equipped to handle.
>
> To be clear, I will not be satisfied with a markup-only approach. No
> matter how complex it is, it does not handle all the use-cases I care about.


Which of your use-cases have not been met? So far I've seen only "I want X,
Y, Z" but not what you need X, Y, Z to achieve that isn't covered by other
simpler proposals or existing features.

I would be fine if we went with a variation of Nicholas' proposal. Let me
> state that new proposal here:
>
>


2. `onpreload` event fired on any script which has `preload` attribute or
> property on it at the time its (pre)loading finishes (and execution is thus
> suppressed). Otherwise, not fired.
>

What do you need to do that requires this event?

I don't understand what this proposal has over Hixie's proposal other than
proposed-by-Kyle :)


> It continues to be wrongly asserted that the current `onload` event on
> scripts is sufficient. It is not. It's a chicken-and-the-egg, because
> `onload` is fired strictly when scripts have loaded AND executed. We need
> an event to tell us when it's ONLY loaded but strictly HASN'T executed yet,
> which makes `onload` insufficient.


For the rest of this discussion I need you to understand that saying "We
need x" is not proof enough that we need x. Please explain why it's needed
and how you would use it to do something that couldn't be done without it.

<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>

The above doesn't need an extra event. In fact, your proposal doesn't need
an extra event, I could remove the preload attribute and wait for onload,
it doesn't matter if the script has been preloaded or not. Maybe I'm
missing a use-case, but I need you to show what that is.


> It's quite clear and obvious how the `onpreload` event is useful to
> script-based loading.


Don't tell us it's clear and obvious, just make it clear and obvious.
Provide an example that requires it.

Before we look closer at this load-but-don't-execute pattern we need a good
reason. One that isn't already covered by the #1 idea in the first email +
link[rel=subresource] + dynamic script adding.


> > Given the above, is there a usecase that isn't catered for by
> "dependencies" and existing preloading features?
>
> Yeah, consider this scenario: I want to preload "1.js" and "2.js", but I'm
> not sure right now if I'll execute "1.js", or "2.js", or both. The user
> behavior will determine that. For instance, if they select tab #2 in my tab
> set, I'll go ahead and execute "1.js", and if they scroll way down on my
> page, I'll execute "2.js".
>
> The conditions under which a preloaded script gets executed cannot be tied
> ONLY to the loading of some other script. There has to be a way to tell a
> script "just preload now, I'll let you know when it's time to execute, if
> ever." If we don't have a good script-based solution for that (no, markup
> alone is not enough), then it fails my needs.
>

Firstly, we need proof that parsing is enough of an overhead
to warrant downloading-but-not-parsing. You could simply load the script
but not call the function that does stuff. But if you did want to do that,
you could:

   - Add <link rel="subresource" href="my-script.js"> for every script you
   want to load but not execute
   - When you want to execute, create a script element and add to the
   document (you can use onload to track execution)

If you have multiple files, add multiple link[rel=subresource]s, if they
need to be executed in a particular order, use the attribute from Hixie's
#1 proposal.


> > Sorry to keep being Mr Use-case, but what do you need to do that isn't
> catered for? You can call markNeeded() when you want the script executed &
> both a promise and the script's "load" event will tell you when it's done.
> Why would you need to know when it's downloaded but not executed?
>
> No, as stated above, the `onload` event will NOT tell me when it's only
> loaded but not executed. `onload` only fires after execution.
> Chicken-and-the-egg.
>

Yes, as stated, but no "why" was provided.


> Where would this promise come from that I could listen to (instead of
> listening for an event)? Would the creation of a script element
> (`document.createElement("script")`) give me the promise? Would the setting
> of `whenneeded` property on the script element return me a promise?
>

As shown in the example, calling markNeeded on the script element would
give you the Promise. However, you could also use the onload event. The
promise is provided for ease of use, and all new APIs with an async
success/failure should provide a Promise.


> > Can you provide a comparison that shows another suggestion to be simpler
> than both of Hixie's proposals and match/beat it's performance?
>
> Those are not the only (or even primary) concerns from where I sit. We
> don't just need "another mechanism". We need, finally, a mechanism that
> lets a script loader handle 100% of whatever niche or complex use-cases it
> might be presented with.
>

Provide some.


> For instance, it's impractical that a script loader could come up with
> unique ID's or class-names (for the `dependencies` or `fullfills` ideas) on
> dynamically generated script elements, because of the undue burden of
> searching the current DOM to make sure what you generate doesn't already
> exist (or the CMS case, for instance).
>

If we use CSS selectors, it could be
dependencies="script[src=url/to/script.js]". Nothing unique needs
generating. Class names can be used for grouping and DRY, but a script
loader wouldn't have this issue.

To summarise, here's what we need:

   - A practical benefit to loading-without-parsing that can't be done with
   link[rel=subresource] + dynamic script insertion + Hixie's #1 idea
   - A practical requirement for the onpreload event, something that cannot
   be done without it


More information about the whatwg mailing list