W3C home > Mailing lists > Public > whatwg@whatwg.org > August 2013

Re: [whatwg] Script preloading

From: Jake Archibald <jaffathecake@gmail.com>
Date: Thu, 29 Aug 2013 17:42:56 +0100
Message-ID: <CAJ5xic_hdUbcHuL=W_OtuB7P_tWQ6+Ym4csV_n_r2keXHcNYLA@mail.gmail.com>
To: Ian Hickson <ian@hixie.ch>
Cc: "whatwg@whatwg.org" <whatwg@whatwg.org>
On 27 August 2013 22:55, Ian Hickson <ian@hixie.ch> wrote:

> On Tue, 9 Jul 2013, Bruno Racineux wrote:
> >
> > Why not simply load all such scripts early in the <head> with 'defer',
> > which preserves the dependency order as determined by your app. Using
> > 'defer' in head scripts is actually a very good way to preserve script
> > order with non-blocking scripts. And by loading the scripts very early
> > in the <head>, the possibility of a incurred significant delay of
> > DOMContentLoaded, for an eventual large script not yet downloaded, is
> > minimal to none.
>
> This doesn't seem like it handles all the use cases (e.g. T and U).
>

Worth noting that defer is busted in IE9 and below, to the point where it's
unusable https://github.com/h5bp/lazyweb-requests/issues/42


> > I would also strongly favor restoring the previous spec portion of
> > 'defer' which allow to have defer on inline script blocks (i.e. if the
> > src attribute is not present). I don't know why this html4 functionality
> > was removed from html5?
>
> Well, primarily because basically nobody implemented it, but also, because
> it's not clear what the point is. Why would you need it?
>

I like my scripts to be inert, as in have no impact on the page (like
jquery). I use a small inline script to start the work needed for that
page, meaning I know the starting point for all JS interacting with the
page is somewhere in an inline script. This is much easier to maintain than
scripts that trigger themselves ondomready depending on what they see in
the DOM.

I'd have liked defer (to work in IE and) to work on scripts without src. In
your proposal, does this work?…

<script src="whatever.js" whenneeded></script>
...
<script needs="whatever.js">
   activateTheAlmightyWebsockets();
</script>


> On Mon, 15 Jul 2013, Kornel Lesiński wrote:
> > ES6 modules however do not solve the performance problem. In fact they
> > would benefit from UA having a list of all dependencies up front
> > (otherwise file's dependencies can only be discovered after that file is
> > loaded, which costs as many RTTs as the height of the dependency tree).
> >
> > So I think that eventually ES6 modules + link[rel=subresource] could be
> > the answer. The <link> would expose URLs to (pre)load for performance,
> > but modules would handle actual loading/execution for flexibility and
> > reliability.
>
> The ES6 module doesn't address some of the use cases above, as far as I
> can tell (e.g. Q, U) and require a lot of work to handle some of the
> others. But it seems important that anything we add to HTML be designed to
> work with ES6 modules on the long run.
>

There seems to be a lack of data on how modules would work in the browser.
Eg, when/if they block further rendering. Or is that in the doc & I'm just
not getting my head around it?

It'd be great if modules can solve these but also give the UA all the
requirements up front (or maybe that's the job of HTTP2).


> On Wed, 10 Jul 2013, Jake Archibald wrote:
> >
> > If "dependencies" took a CSS selector it could be:
> >
> > <script dependencies=".cms-core" src="cmd-plugin.js"></script>
> >
> > Now the number of scripts with class "cms-core" can change between
> > versions of the CMS but the plugin still waits for them all. No ID
> > generation needed.
>
> Using a selector is an interesting idea.
>
> It makes it harder to detect and prevent loops, but not fatally so.
>

I'm not sure it's possible to get into loops with this. I imagined
dependency resolution to happen once, on element creation or adding to
document (whichever happens latest). So with:

<script src="a.js" needs="script[src=b.js]"></script>
<script src="b.js" needs="script[src=a.js]"></script>

…the first script would have zero dependencies, because the selector
matches zero elements. The second would depend on the first, so the
execution order is a.js, b.js. The thing I like about the selector thing is
you can very easily get (almost) async=false behaviour:

<script src="a.js" needs="script"></script>
<script src="b.js" needs="script"></script>
<script src="c.js" needs="script"></script>


>   <script> elements get a new whenneeded="" attribute, which delays the
>   execution of the script until the <script> element's execute() method is
>   called. (This essentially provides the same as the "preload"
>   suggestions.)
>

execute() should return a promise that resolves when the script
successfully downloads and executes. Also, should there be an event on the
script element when the script has downloaded, but not executed (like IE
used to have)?

(there's probably a better name than whenneeded, but I can't think of one
right now)


>   <script> elements also get a new needs="" attribute, which takes a list
>   of URLs. A <script> won't run (even if you call execute()) until all the
>   <script src=""> elements referenced by its needs="" attribute are
>   themselves ready to run. For example:
>
>      <script src="b.js" needs="a.js"></script>
>      <script src="a.js" async></script>
>

It seems weird to refer to "needs" by url, but still require script
elements for those needs, I'd rather use IDs (or selectors yey!). Also, I'm
not sure we need to deal with the case above, where the script with the
dependency appears in the DOM prior to the script it depends on. Avoiding
this avoids the circular dependency problem (see my selector example above)

Does a script with "needs" but not "async" block rendering? I hope not.


>  <script whenneeded="jit"> is a special mode where instead of running once
>  the script's dependencies are met, it additionally waits until all the
>  scripts that depend on _it_ are ready to run. ("Just in time" exection.)
>  (The default is whenneeded=asap, "as soon as possible" exection.)
>
>  You can manually increase or decrease a dependency count on <script>
>  elements by calling incDependencies() and decDependencies().
>

I'm not sure we need these. The use-cases could be dealt with by some fancy
use of the promises returned by execute & the potential
"loadedbutnotexecuted" event. It won't be as few bytes, but I think the use
cases are pretty niche.

I'm keen on all this, but I'd like to hear from the ES modules guys. I
wonder how many of the usescases in this thread they hit.

Cheers,
Jake.
Received on Thursday, 29 August 2013 16:43:29 UTC

This archive was generated by hypermail 2.3.1 : Thursday, 29 August 2013 16:43:31 UTC