[whatwg] Script preloading

Kyle Simpson getify at gmail.com
Thu Jul 11 15:14:34 PDT 2013


> I am interested to see how the above use-cases would be met in your
> counter proposal(s) to see if it would be simpler/faster. If LabJS is
> a requirement, it must be factored in as a unit of complexity and
> load-step.
> 
> Please do this rather than declare anything to be insufficient without
> reasoning.

It's gonna take a lot of time to write proof-of-concept code for all the different nuances and use-cases I've brought up. I'm presenting 2 here. There's more to come.

Unfortunately, Jake made a number of simplifying assumptions, or simply missed various nuances, in his attempt to combine/reduce/restate my use-case list. I'm not ascribing any ill-will to that, but just pointing out that it's not nearly as easy as his list might suggest.

I've spent some time trying to put together a first set of code comparisons between the `<script preload>` proposal I've put forth and the `<link rel=subresource>` + `<script dependencies=..>` proposal Jake is advocating. This is by no means an exhaustive comparison or even nearly stating the many issues I forsee, but it starts the discussion with actual code instead of theoretical concepts.



https://gist.github.com/getify/5976429


There's lots of code comments in there to explain intended semantics, outstanding questions/issues, etc.



Some observations/clarifications:

* "ex1-getify.js" is my attempt at creating a simple `loadScripts()` script loader that loads scripts in parallel, but executes them strictly in request order, serially.

  --> ONE KEY NOTE: my implementation accomplishes my use case #11 quite easily, in that it doesn't start executing any of the scripts in a group until ALL the scripts are finished preloading, thus minimizing any gaps/delays between them running. I'm able to do this easily because every script fires a preload event, so it's trivial to know when all such events have fired as my clue on when to start execution.


* "ex1-jaffathecake.js" is my attempt at doing something as close as possible using Jake's proposed way. I've asked for his feedback on this code, so until he has a chance to feedback, take it with a grain of salt.

In any case, the code is certainly simpler, but it's missing a KEY COMPONENT: it's NOT able to assure what my script loader code does. That is, "a.js" might run long before "b.js" runs, whereas in my implementation, there should be almost no gaps, because "a.js" doesn't run until "b.js" is loaded and ready to go.

Jake suggested a hack to address this use-case which is based on the idea of hiding the whole page while scripts load with gaps in between. This hack is not only terribly ugly, but it also misses a big point of my motivation for that use-case.

The point is NOT "can we hide stuff visually", it's "can we make sure stuff doesn't run until EVERYTHING is ready to run".

Moreover, as I note in the code comments, it is impossible/impractical for a generalized script loader to be able to determine all or parts of a page that it should hide, and under what conditions. The script loader is agnostic of what it's loading, and it certainly is supposed to be as unobtrusive to the hosting page as possible, so it's out of the question to consider that a script loader would go and do nuclear-level things like hiding the document element.

The key thing that's missing in Jake's proposal that's necessary to address this use-case is that there's no way to be notified that all the scripts have finished pre-loading. Instead, his approach obfuscates when things finish loading by simply letting the <script> element internally listen for loads of its "dependencies".

This is what I mean when I keep saying "chicken-and-the-egg", because I want to know everything's finished preloading BEFORE I start the execution cursor, but in Jake's world, I can't know stuff is finished loading until after I observe that it's running.


* "ex2-getify.js" is a more complex script loader, that takes into account the ability to have "sub-groups" of scripts, where within the sub-group, ASAP execution order is desired, and serial-request-order execution order is desired across the various sub-groups.

Simply stated: All of C, D, E, and F scripts load in parallel. When it comes to execution, "C.js" runs, then a sub-group of "D.js" and "E.js" will run, where within the sub-group, either D or E runs first, ASAP (they don't block each other), and then when both have run, finally, "F.js" executes.

This scenario is quite common: I load jquery.js, then I load 4 jquery plugins (which are independent), then I load my page's app.js code runs. jquery.js is the firs to execute, then the 4 plugins run in ASAP order, then when they're all done, finally my app.js code executes.

Also, this more complex script loader listens for `script.onerror` events, and if it detects one, it aborts any of the rest of the execution.

Any such error handling is trivial in my loader, because I am always fully in control over which script is loading at any given time.


* "ex2-jaffathecake.js" is again my attempt to address this use-case using Jake's proposal. The major outstanding question here is how `dependencies` will respond to loading errors. It's unclear, thus far, how much sensitivity (if any) this mechanism would have to loading (network) errors, compile-time (syntax) errors, and run-time errors. The less sensitive it is, the more complex this code needs to be made to handle those use cases.





--Kyle






More information about the whatwg mailing list