This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 14194 - Request: specification for script preloading
Summary: Request: specification for script preloading
Status: RESOLVED WONTFIX
Alias: None
Product: HTML WG
Classification: Unclassified
Component: HTML5 spec (show other bugs)
Version: unspecified
Hardware: All All
: P2 enhancement
Target Milestone: ---
Assignee: This bug has no owner yet - up for the taking
QA Contact: HTML WG Bugzilla archive list
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-09-17 19:59 UTC by Kyle Simpson
Modified: 2016-04-18 20:05 UTC (History)
11 users (show)

See Also:


Attachments

Description Kyle Simpson 2011-09-17 19:59:48 UTC
There's been much discussion, both on and off list, about the use-cases for script preloading. In particular, several proposals were formalized here:

http://wiki.whatwg.org/wiki/Script_Execution_Control

After speaking with several developers at Mozilla to come to some agreement, we would like to ask that a mechanism for script preloading be specified.

To be clear, what we're asking for is a mechanism by which:

1. from JavaScript code, one or more external JavaScript file(s) can be requested to download, but the user agent will *not* execute them automatically upon load completion.

2. Scripts being preloaded must be loaded in parallel in a separate queue (so as not to block or be blocked by) the queues used for `defer`, `async`, "ordered async", etc.

3. The user agent needs to fire an event for each script element which indicates that the script has finished loading (but not executed). This event must fire even if the script element is already in the cache and preloading is moot.

4. The user agent must allow a script that has finished loading (been "preloaded") to be executed synchronously.

The suggestion would be to take one of the two main proposals listed in the URL above as the starting point for such a mechanism.

--------------

Discussion:

One of the most valid concerns that some user agents have expressed about such a mechanism revolves around *my* proposal, which is to standardize IE's "implicit preloading". Implicit preloading carries with it a potential "risk" of abuse or misuse by developers whereby many scripts could be preloaded (kept in memory) but never used, thus wasting precious bandwidth and memory (especially on mobile devices). This concern mainly arises because implicit preloading could happen without the author even knowing or expressing intent to do so.

The alternate proposal detailed in the above link (from Nicholas Zakas) was for "explicit preloading", which would not activate preloading for a requested script unless the web author specifically sets a "preload" flag on the element. Explicit preloading reduces the chances that a web author can accidentally misuse the mechanism with unintended waste of resources.

OTOH, the implicit loading mechanism proposal is fully compat with IE (since v4), which is attractive for web authors because it means compat instead of browser feature-forking.

A recent discussion thread expressed great concern about of "double-fire" issues (in Opera and IE9 standards mode) with web authors *incorrectly* listening for both the `onload` and the `onreadystatechange` events but not filtering that both events will fire for a script element. While this is clearly web authors behaving incorrectly (conflating the two event handlers), the concerns are great enough that it was felt that `onreadystatechange` could *not* be added to script elements (as IE has).

So, if the "implicit preloading" proposal were to be considered, the people I spoke with at Mozilla feel that the event name would have to minimally be different than `onreadystatechange`, to break with that existing web content bugginess. For instance, near-complete compat with IE's preloading behavior could be achieved by taking all other parts of the proposal the same, but changing the event name to `onreadystate` (dropping "change"). While not perfectly ideal in terms of compat, this wouldn't be too onerous for script loader authors to feature detect the appropriate event name to listen for.

On the whole, I probably now lean toward suggesting "explicit preloading" like Zakas' proposal has. This is unfortunate for non-compat, but it addresses several of those arguments above in a clean'ish way.

The developers I spoke with at Mozilla feel there is merit to script preloading, but they want the spec to define a mechanism for it before they implement it. Their only concern was that the specification not be so limiting so as to prevent the user agent from having some leeway in how such a mechanism is actually implemented/managed.
Comment 1 Boris Zbarsky 2011-09-19 01:15:02 UTC
One thing I said that did not come clear in comment 0: the spec needs to allow a way for the UA to discard preloaded scripts under memory pressure in a spec-conformant way.
Comment 2 Kyle Simpson 2011-09-19 04:06:53 UTC
(In reply to comment #1)
> One thing I said that did not come clear in comment 0: the spec needs to allow
> a way for the UA to discard preloaded scripts under memory pressure in a
> spec-conformant way.

Right, sorry for under-reporting the position. I was going on the part of our discussion which seemed to suggest that if an explicit preloading mechanism were in place, maybe the "I'm gonna throw out all the preloaded scripts" wasn't so much of a hard requirement.

In any case, if the UA can throw out the scripts, then this is an important addition to the requirements stated in comment #0... that the mechanism must make that clear to a developer that the script has gone from "preloaded" back to "unloaded" in some way (by event -- preferably -- or by property change). That way, a script loader could see "oh, crap, my preloaded scripts are gone, i've got to reload all of them and try again".

In fact, if the UA were constrained to choosing to throw away *all* preloaded scripts (not just picking and choosing some to throw away), the simple and sufficient approach would be a single global event like `preloadDiscarded` or something like that, and would actually be even easier for the script loader than having to deal with the case of each individual script having an event like "un-preloaded".
Comment 3 Nicholas C. Zakas 2011-09-21 18:28:05 UTC
Script preloading is already way overdue. We can preload images, CSS, even video, and I'd really love to formalize how to do so with scripts as well. 

I'm not sure why this would have to be more complicated than preloading an image. If I do:

    var img = new Image();
    img.src = "foo.png";

This preloads my image and (I think) keeps it in memory. Is that memory ever cleaned up if I don't use the image? What about with videos? How about stylesheets that are disabled?
Comment 4 Boris Zbarsky 2011-09-21 18:34:24 UTC
> This preloads my image and (I think) keeps it in memory.

It keeps the compressed image data in memory (or on disk, of course; see below).  Decompression can happen synchronously when you use the image; this can lead to significant pauses (order of seconds) when the image is actually used.

Are you OK with only preloading compressed representations of scripts and having a noticeable decompression or fetch delay on use, like for images?

> Is that memory ever cleaned up if I don't use the image?

I can't speak to other UAs, but in Gecko it's not.  Yet.  We're considering changing that.  Of course the OS can also cause it to be swapped to disk, in which case it has to be read from there too via a page fault.

Again, is that acceptable for script preloading?
Comment 5 Nicholas C. Zakas 2011-09-21 18:39:32 UTC
I would be okay with the delay provided its on the order of magnitude of pulling from cache and executing. By that, I mean I'd like it to be no slower than if the script were already cached and you ran this today:

    var script = document.createElement("script");
    script.src = "foo.js";
    document.head.appendChild(script);
Comment 6 Boris Zbarsky 2011-09-21 18:48:18 UTC
Yeah, it would be comparable to that, presumably.
Comment 7 Kyle Simpson 2011-09-21 18:48:52 UTC
(In reply to comment #4)
> > This preloads my image and (I think) keeps it in memory.
> 
> It keeps the compressed image data in memory (or on disk, of course; see
> below).  Decompression can happen synchronously when you use the image; this
> can lead to significant pauses (order of seconds) when the image is actually
> used.
> 
> Are you OK with only preloading compressed representations of scripts and
> having a noticeable decompression or fetch delay on use, like for images?

Given the choice between no preloading and preloading as you suggest, I pick preloading as you suggest, for sure.

But that type of delay, especially on mobile (limited CPU, etc) basically can act to decapitate the whole purpose for preloading, which is to reduce (as much as possible) the delays (downloading, parsing, compiling, etc) when you want to synchrously execute a script.

Are you suggesting that this delay would still be synchronous upon attempt to execute the preloaded script?

Also, I've looked at a lot of waterfall diagrams in a whole bunch of different browsers, devices, connections, etc. I've never seen anywhere near orders-of-magnitude of seconds for the amount of time the browser spends "decompressing"  a gzip'd script. Even on large JS files like 300k+, the most I've ever seen the "processing" stage of a script take is a couple hundred ms.

Can you elaborate on any scenario by which gzip unzipping would take seconds to perform (even on low-CPU mobiles)?


> > Is that memory ever cleaned up if I don't use the image?
> 
> I can't speak to other UAs, but in Gecko it's not.  Yet.  We're considering
> changing that.  Of course the OS can also cause it to be swapped to disk, in
> which case it has to be read from there too via a page fault.
> 
> Again, is that acceptable for script preloading?

I think strictly speaking for the purposes of this proposal, it's "allowable", but certainly far far short of ideal. It will probably act to moot most (but not all) of the benefits.

It seems like keeping preloaded scripts compressed in memory is missing a significant opportunity to perform parsing and compilation (and even static analysis, like type inference, etc) on a preloaded script that is just sitting there idle, waiting to be executed sometime in the future.

Moreover, what if the JS is served uncompressed in the download? A lot of JS is still sent out without gzip on the wider web. Are you planning to compress such uncompressed scripts before keeping them in memory, thereby "charging" the time cost both for compression and for decompression to the client?

If not, you're saying that you're ok storing those uncompressed scripts in memory as-is, but not the ones which were downloaded via gzip? That seems a little strange of a distinction to me.
Comment 8 Boris Zbarsky 2011-09-21 19:20:11 UTC
> But that type of delay, especially on mobile (limited CPU, etc) basically can
> act to decapitate the whole purpose for preloading

Yes, that was exactly my point.

And yet mobile is also where memory pressure is the biggest problem.

> Are you suggesting that this delay would still be synchronous upon attempt to
> execute the preloaded script?

It'd have to be to give you sync-execute semantics, right?

> Even on large JS files like 300k+, the most I've ever seen the "processing"
> stage of a script take is a couple hundred ms.

300K is a medium size JS file, from what I've seen...  Heck, jQuery is about 100K even minified, before compression. The difference between several hundred ms and 1s is just a matter of different device.  But yes, the point was just that there would be a quite noticeable pause.  200ms is way above human perception level.

I just tried decompressing gzipped minified jquery on a pretty new tablet, and it took me about 100ms.  On a slower device, it would of course take longer.  And there are plenty of JS files larger than minified jquery out there.

> It seems like keeping preloaded scripts compressed in memory is missing

The point is that in low memory situations we'd like to be able to fall back on discarding all that compiled code, static analysis information, decompressed data, etc.

> Are you planning to compress such uncompressed scripts before keeping them in
> memory

In low-memory conditions, probably yes.  We're already moving toward compressing them before putting them in our memory and disk cache, no matter how the server sent them.
Comment 9 Robin Berjon 2013-01-21 15:59:55 UTC
Mass move to "HTML WG"
Comment 10 Robin Berjon 2013-01-21 16:02:41 UTC
Mass move to "HTML WG"
Comment 11 Travis Leithead [MSFT] 2016-04-18 20:05:14 UTC
HTML5.1 Bugzilla Bug Triage: Incubation needed.

Wondering though, if <script type="module"></script> fills this need? 

This bug constitutes a request for a new feature of HTML. Our current guidelines, rather than track such requests as bugs or issues, is to create a proposal for the desired behavior, or at least a sketch of what is wanted (much of which is probably contained in this bug), and start the discussion/proposal in the WICG (https://www.w3.org/community/wicg/). As your idea gains interest and momentum, it may be brought back into HTML through the Intent to Migrate process (https://wicg.github.io/admin/intent-to-migrate.html).