- From: Kyle Simpson <getify@gmail.com>
- Date: Mon, 30 May 2011 14:52:17 -0500
[Apologies for being out of the loop on this thread thus far, as I was one of the main proponents of it earlier this year. I am now going to dive in and offer some feedback, both to Ian's comments as well as to others that have replied. I also apologize that this will be an exceedingly long message to address all that Ian brought up.] > Problem A: > > On Tue, 8 Feb 2011, John Tamplin wrote: >> >> simply parsing the downloaded script takes a lot of time and interferes >> with user interaction with the UI, so as awkward as it seems, >> downloading the script in a comment in the background, and then >> evaluating it when needed does provide a better user experience on >> mobile devices. >> >> See >> http://googlecode.blogspot.com/2009/09/gmail-for-mobile-html5-series-reducing.html >> for the official blog post about this technique. > > The problem here seems to boil down to "we want our script-heavy page to > load fast without blocking UI, but browsers block the UI thread while > parsing after downloading but before executing". > > .... .... .... .... ..................................... There's a whole bunch of other comments later in this thread, as well as in the original threads, which seem to focus on the performance side of this proposal's justification. I think we've beat this horse to death a dozen times now, so I think belaboring it further is counter-productive. But you must understand that performance impact of execution/parsing was only PART (and in fact in my mind, only a smaller minority part) of the justification for wanting to have separatable download vs. parse/execute. However, *performance optimizations* as a general goal of web applications is much more broad than just the question of if a background thread can handle parsing of a script in a non-UI-blocking way. For instance, the whole concept of dynamic script loading (loading multiple scripts in parallel, but executing them in order) is all about performance optimization. THAT is a much more compelling set of arguments for this feature being requested. So, *performance* is important, but the performance of parsing/execution is perhaps a little less important in the overall scheme of things. This thread seems to be so easily side-tracked into the minutia of conjecturing about background thread parsing and different implementation details. I wish we could just take as a given that parsing/execution of a script are not zero-cost (though they may be smaller cost, depending on various things), and that ANY control that a web performance optimization expert can get in terms of when non-zero cost items happen is, in general, a good thing. > PROPOSALS > > The simplest solution to problem A seems to be to have the browsers do the > script parsing on a background thread, rather than blocking the UI. This > requires no changes to the specification at all. It can be combined with > lazy downloading by inserting a <script> node when the script is needed; > basically, it is combining the "downloading" and "parsing" background > steps into one. The thread also makes a lot of references to <script async> and how that seems to be the silver-bullet solution. The problem is two-fold: 1. <script async> only effectively tells a user-agent to make the loading of that script resource happen in parallel with other tasks, and that it can choose to execute that script at any point whenever it feels is good. This means that the script in fact can be executed still before DOM-ready, or between DOM-ready and window.onload, or after window.onload. Thus, the script's execution effects the page's rendering in an intermittent way, depending on network speeds, etc. <script defer> on the other hand specifically tells the script to wait on its execution until after onload. 2. <script async> only effectively delays a script if that script is completely self-contained, and doesn't have any other dependencies (such as needing two scripts to defer/async themselves). If you need to tell two or more dependent scripts to wait until "later" to execute, <script async> is not helpful, as (per spec) the execution order of the scripts is not guaranteed. Dynamically loading a script element, and setting async=false, will ensure execution order, but will not alleviate the problem that execution of the script (and its affects thereof) may happen earlier than they would like (like during critical page-loading activities, animations, etc). > There doesn't seem to be any need to treat them as separate steps for > solving problem A. I believe in the thread earlier in the year, it was (mostly) a consensus that while parsing and execution were separate, all that was really desired was to separate (aka, delay) execution from the loading, which had the side effect of providing a larger window of buffer between load-finished and script-executing in which parsing will occur. This allows the user-agent to defer parsing to a later time, perhaps even entirely deferred until the page asks for a script to be executed. As tech currently stands, because loading is (almost) immediately followed by parsing and then execution, there's no way to prevent the parsing/execution from happening right away, because they're all smashed together into one (mostly) inseparable sequence. The feature request is to be able to stretch out the execution to a later, on-demand time, which will also allow parsing to happen somewhere in between, with less of a chance that it affects performance. > Given that script execution (as opposed to the preprocessing that occurs > before execution, including parsing and compilation) can be trivially > fast (e.g. by making the script do nothing but expose an object), what is > the benefit of delaying the execution? There's a whole bunch of comments in this thread which allude to the idea that the problems being expressed are simple to fix if authors just change how they write their code. While that may (or may not) be true, it's irrelevant to the real-world web we're trying to fix *right now*, because the vast majority of JavaScript is not written this way (such that it's entirely modular and causes no side-effects on "execution"). Moreover, it's an anti-pattern to suggest that an author must, to achieve better performance, stop referring to a third-party script location on a CDN (for shared caching benefit), and must instead host that third-party script themselves, AND modify that script in such a way as to insulate it from causing immediate effects upon load-execute. The spirit of the main proposals is to be able to load-but-not-execute (or, load-but-have-no-execution-side-effects) *any* script, even ones which we do not control, or are not in a position to modify (and then be forced to maintain update patches to). Continuing to suggest in this thread that the solution is to modify the script is both aggravating and unhelpful, as it completely misses the most important majority use-case: loading (almost) all the current JavaScript on the web. > Given that the time the script takes to execute is already under the > control of the author, and can be trivially short, this solution doesn't > seem to address problem A: anything the browser does in the background > before the <script> is inserted can just as easily be done in the > background after the <script> is inserted. Huh? This argument makes no sense. You're referring to my proposal to standardize what IE already does, which is that it loads a script but will not execute the script until the <script> element is actually added to the DOM. The purpose of that proposal is that I as an author can wait until a much later time (like when a user clicks a button) to decide that I now want a script executed, at which point I then add the corresponding script element to the DOM to express that I'm ready for it to be executed. Whether the parsing happens right at the point where I add the script element to the DOM, or whether it's happened at some point between then and the point earlier when the script arrived (finished loading), the point is that the script parsing didn't HAVE to happen right at the moment the script finished loading. In fact, as we agreed (mostly) in the earlier thread from back in Jan/Feb, an author being able to signal to a user-agent that parsing CAN be deferred is a generally useful thing, such that if a user-agent finishes download of a script but the script isn't yet flagged for execution, the user-agent can see this as a signal that this code is in fact lower priority, and it can wait to a later/idle time before tackling it. Compared to now, when a user-agent must parse and execute it right away, this should be an obvious win in terms of giving the user-agent a longer/more-flexible window in which to spend find time to spend on parsing that script. >> IE goes one step further, which I think is useful, which is to give a >> `readyState` (and `onreadystatechange` event handling) to the script >> element, which notifies the code of the state of this "preloading". Why >> this is useful is that you may choose to wait until all scripts have >> finished loading before starting to execute them. Being notified of when >> they finish loading (but not executing) can be a very useful addition to >> this technique. > > The problem with this technique is that there's no guarantee that the > script will be downloaded at all -- it depends on the UA's belief about > what will lead to the best experience. For example, if the system has idle > cycles, it might happen sooner than if the UA is extremely busy already. > That's rather the point of the feature. :-) The user-agent can decide not to load a script, regardless of the use of this preloading or not. If I create and append to the DOM a <script> element, that requests an external resource, and the user-agent is sufficiently convinced that requesting such a resource is not a good idea, the user-agent will in fact not request it. So I'm not sure why that's an argument against the before-DOM-append-preloading mechanism that IE does, and the spec suggests? The user-agent can't be forced into downloading a resource, so it's a moot argument to suggest that the lack of a load-guarantee is a mark against the preloading technique. I don't see any evidence there's any more guarantee between either case. If I as an author am using script before-DOM-append-preloading, and I'm waiting on a signal to tell me that it's completed, and that signal never comes (because the user-agent feels it's a bad idea to load the script), then I'm in exactly the same consequence (that my page's script won't load/execute) as if I was NOT using any preloading, and had just made a <script> to request the code, and the user-agent had ignored my request. Either way, my page won't ever load and run the script. > Also, readyState isn't actually especially useful here, at least not in > the context of problem A. Consider the two possibilities: (1) by the time > you want to run the script, it is already loaded, and (2) by the time you > want to run the script, it is not yet loaded. In (1), you can insert the > element into the DOM and it'll just work. And in (2)... well you want the > script to run ASAP, so why wait? You just insert the element into the DOM > and as soon as it can, the UA will execute it, and so again, it just > works. No need to track when it is ready. Tracking when it's ready is useful in the case of more than one script, where the author is negotiating when to execute things because of dependencies. > If you need to track when it's ready to make sure you execute another > script after it, then just using the 'load' event on <script> is > sufficent: just wait for the previous script to have run, then insert the > one you care about. This suggestion is way more complicated than you make it out to be, unless the dependency chain is only simple and linear (B.js only depends on A.js, etc). It's quite common for a script to have more than one co-dependency. Example: C.js uses functions from (thus is dependent on) both A.js and B.js. All 3 are pre-loaded in parallel. C.js cannot be directly executed inside of the `onload` of either A.js or B.js, as it must be in a gate where BOTH have finished. So, an external flag registry (aka, some script loader, or global variables, etc) for A and B must be employed, which is consulted in both `onload` handlers, such that only in the SECOND of those two handlers being run (thus A and B are in fact already executed), is C then executed. -------- Also, your suggestion completely leaves out an important use-case... I may not want to execute *any* of the 3 scripts, until all of them are present. In other words, I may not be satisified if A and B both run, but C isn't yet ready, and doesn't run until later, because that gap in execution may (depending on my scenario) leave my scripts in an in-between state that is undesirable. If I want to wait until A, B, and C have finished loading, before beginning to execute the group of them, then I *have* to have some signal (like `readyState`) of each of them finishing loading. `onload` isn't sufficient for that purpose, because it only executes after the script has run, not after it's loaded (as its name confusingly implies). > But really, it seems better to structure your scripts > so that they don't do anything when they are run except expose a callback > that you can run when you want the code to run. Sure, it's better. But it's also unrealistic to expect all the millions of scripts on the web to change simply because I want my pages to load faster. And as I said, it's untenable to suggest that my ONLY remedy is to self-host and modify such scripts. We need a more flexible load-and-execute mechanism to bridge the gap in a way that respects the goals of those of us who obsess about web performance optimization. > (As a side-note, in the HTML spec the words "shall" and "will" don't have > any normative meaning. See the "Conformance requirements" section.) > > We could change "may" to "must", but it would merely constrain > implementations further: instead of being able to optimise in certain > situations by _not_ fetching scripts that might never be used, it would > force the network to be used in these situations. That seems like a loss, > and does nothing to address problem A. User-agents still have the freedom to decide not to start the preload right away. Nothing in the proposals suggests that preload must immediately occur. It simply suggests that, unless there's some overriding reason why a user-agent intends never to fetch a script, that it MUST start fetching the script at some point at, or later than, when the script's `src` attribute/property is set. Also, it clearly DOES assist problem A, because (as I said above) it gives a larger window between the finish of a download and the time when the script is requested to be executed, at any point in between of which the parsing could occur. The bigger that window of freedom for the user-agent to "schedule" the parsing, the more likely it is that the parsing won't occur in a time-sensitive period of time (such as while an image is rendering, or while an animation is occuring). >> The major issue I have with the way the spec is written is that there is >> no way to feature detect this capability. > > That is entirely intentional: it's a UA optimisation; we don't want to > expose those, as it constrains what UAs can do to improve. This is nonsense. Just because you make something detectable doesn't mean that it's handcuffing the UA for the future, as any changes (either in build-features or in run-time performance detection and adjustment) would affect that feature-test in a predictable way. In fact, the whole point of detection is so that assumptions aren't made, and that only when something is actually true can another something proceed to occur. I'd argue that the behavior of how a script is loaded is precisely the sort of thing that should be detectable, so that script loaders (like LABjs) don't have to make assumptions about a browser based on brittle inferences or worse. Example: let's assume I want to only use some behavior on a page if I can detect that the user-agent rendering that page is of sufficient capability performance-wise to do so. One such detection I may want to make is to see if the UA is capable of doing preloading. If it is, then I may opt for the more complicated series of parallel-downloaded scripts for some complex widget. If it's not, then I may want to assume (especially if I'm dealing with a mobile-targeted page) that I should serve up a simpler set of behavior (less scripts, fewer dependencies), and thus not rely on the optimization of preloading being available. Clearly, "preload" functionality in that light is both a UA optimization *and* a author-centric optimization, and it's an obvious benefit if an author can detect that such an optimization is available for opt-in from the UA. I can't hardly think of any argument (other than maybe security/privacy) where exposing a detection for any feature/behavior of a browser is a bad thing. The more detections are available to authors, the more they will properly author their pages around feature-tests, instead of around ugly/hacky UA sniffing, etc. There are clearly *many* things which UA's do that aren't necessarily that useful to expose detects for, but I think it's absurd to suggest that exposing a detect for a performance behavior is bad thing, in a case where a UA behavior has a clear overlap with something authors want/need to detect and build around. >> <html> >> <head> >> <script src=a.js noexecute onload="..."> >> <script src=b.js noexecute onload="..."> >> <script src=c.js noexecute onload="..."> >> </head> > > What would the onload="..."s be? I don't understand the benefit of not > executing the scripts here. If you want your scripts to not do anything, > just have them not do anything except expose a function that you can call > whenever you want the actual code to run. This pattern was debunked back in the Jan/Feb thread, because `onload` doesn't fire when the script finishes *loading*, but when it finishes executing. So such an example would cause none of the 3 scripts specified to ever run, unless some other script (not listed) came along and started the execution sequence by somehow forcing "a.js" to execute. Again, in that Jan/Feb thread, I asserted (and IIRC it was uncontested to any reasonable degree) that the only practical use for script preloading as proposed is for dynamic script loaders (those which insert script elements dynamically) and that the markup-only use case was both impractical and distracting to the conversation. >> Doesn't <link rel=prefetch> mostly address the use-case of >> load-but-don't-execute in markup? > > <link rel=prefetch> doesn't solve problem A because it doesn't give the UA > any hint that the resource is a script it should compile. This is ALSO a distraction because it's merely a suggestion that a resource be prefetched into the cache, not that a script be loaded and ready for execution. "Cache preloading" (the technique of loading a script resource into cache by some hacky means, in such a way that it's loaded but NOT executed, and *then* later executing it by recalling that item from the cache with a normal <script> element) is brittle, hacky, and dangerous for the web (as not all scripts are sent with proper caching headers -- in fact, a recent estimate was ~50% are not, web-wide). <link rel=prefetch> simply feeds into that same sub-optimal "cache preloading" bucket. It's wholly insufficient for the proposers' needs. >> [problem A] has driven crude hacks like the comment hack, which in fact >> precludes the browsers [ever] getting smarter about doing the >> parsing/etc in the background or during idle time. > > I don't see why it would preclude them from getting smarter. The smarts > wouldn't improve the pages with the hacks, but that's ok. It doesn't hurt > them either. It hurts them indirectly because it leads to more and more authors hiding more and more code from the engine (via comment wrapping). It's shooting the engine in the foot so that another performance optimization can be tended to. The better mechanism would allow direct loading/parsing of real (not comment-wrapped) JavaScript and still give the author control over when execution happens. >> This proposal is about a way to hint to the browser that only the >> download part should happen now, and the parsing/execution of the >> downloaded script will happen later, which in fact enables smarter >> browsers to make smarter decisions. > > That doesn't solve problem A: you still end up blocking the UI when you do > the parsing if that's all you change. Sure, but... at least in the case where I was able to direct the execution to happen when I wanted it to, I could, as the author, guarantee that I only do so at a time when nothing else important (like an animation) is happening on the page, so as to mitigate the side-effects. I'm not suggesting that background-thread-parsing is a bad or unhelpful improvement. I'm simply saying that it's not sufficient to meet the needs of the proposers (Nicholas and myself). >> Well, there is only a certain amount of processing power to go around. >> No matter how well it is implemented, time spent parsing is time that >> can't be spent doing other things if the app is pushing the client to >> the limit, and it makes sense to let the app provide hints of when is a >> good time to spend that effort and when isn't a good time. > > It seems like "when there's nothing else going on" is the best time. How > would the script know when that is better than the UA? Because the page's author can suspend certain activities which would be impacted, like animations, video, audio, etc, when it's about to perform some task which might lock up the UI thread. And btw, "when there's nothing else going on" is a gross over-generalization/assumption. The even "better" time is "never". A page's author may be able to detect (something the UA could never do as well) that it's in a condition where some of the code it asked to be pre-downloaded will never actually get executed (at least during this page-view), and so allowing the author's code to simply say that such parsing should never occur (by not ever actually asking the code to execute) is a win in terms of that author's ability to keep a page's device resource utilization to a minimum (gmail for instance wanting to be battery-life conscious, etc). Whether such parsing would happen in a background thread or on the main UI thread, avoiding any unnecessary parsing is a win in terms of device resource utilization. ------- For instance, on page 1 of a site, I may need scripts A and B to download and run. I may also want to go ahead and preload C and D (to take advantage of connection keep-alives, for instance), even though I know that there's a good chance neither C nor D will be used on page 1. NOTE: I *may* need C or D on page 1, but only if a user clicks a special button, etc, so I only want to pay the parsing penalty in those rare cases, and not all page-views. I also may know that either/both of C and D are particularly complicated scripts, and their parsing is something I'd like to avoid paying any penalty for (either in terms of UI locking up or in terms on device resource utilization), unless it's definitely going to be used. On the flip side, for page 2 (which not all users get to), I may know that C and D are definitely required early in the page view, so having them already in cache (to avoid network fetch latency) is a good thing. And it's acceptable (of course) to pay the parsing penalty on *this* page, because I know for sure I now need C and D. This type of performance-savvy thinking is something a web performance optimization engineer can do, but it's likely not something a browser will ever be able to figure out automatically. Bottom-line: Putting the tools in the hands of the engineer to be able to optimize, especially in cases where a browser wouldn't or couldn't, is a performance win in the long-run. > It's clear that the parsing/compiling has to happen between download and > execution, it seems that the browser is in the best position to know when > it could do it with minimal impact on the rest of the system. Making that assumption is rather na?ve given the expounding of use-cases I've been trying to explain throughout this message and in the previous Jan/Feb thread. You could assert that the UA is usually in the best position, but saying it ALWAYS knows better than the author is quite short-sighted. > If you just want it to happen soon but don't care exactly when, we have > "async". <script async> is "as soon as possible", which is in some cases quite different than just "soon". Moreover, the spirit of this discussion is about deferring the execution (and by implication, at least stretching out the window of when parsing can occur)... neither of these are impacted in any meaningful way by <script async>, because a <script async> still parses and executes "immediately" after it finishes loading. In the case of a dynamic script loader adding script elements to the page (again, script loading is the only meaninful context to have these discussions in -- markup-only is moot and irrelevant), <script async> isn't going to execute any sooner or later than just <script>. The *only* functional difference between the two is if execution order will be preserved or not, not the behavior of parsing vs. execution. > If you want it to happen now, then the spec also supports that. "happen now"? How so? > It's not clear why anything else is needed. Because you haven't provided any answer as to how I achieve "happen (much) later" -- you only suggested "now" and "soon". > The "preload"/onpreload part of this seems unnecesssary to solve problem > A: by the time the event fires, all the difficult work is done, and the > execution (the only thing this would allow you to delay, and the only > thing that has to block the UI thread) can be trivial in comparison. This is an incorrect assertion. The earlier Jan/Feb thread arrived at the conclusion that parsing could be separate from execution, and while not directly controlled, could happen at any point in between the load-finish and the execute-start. So, in that sense, the "hard part" (the parsing/compliation) may or may not have happened at the point that the "preload" event is fired. The parsing/compliation could only be forced to happen sooner (if the UA was planning to defer it) if the script was then requested to execute, at which point the UA would have to respond by parsing/compiling before it could execute. Otherwise, the window between load-finish and execute-start could be quite wide, and could allow the UA much flexibility in deciding when such activity should best occur. >> Loading JavaScript onto a page poses several performance issues. > > Which issues? Seriously? Can we not just cite the hundreds of blog posts and books on the subject as prior evidence? The performance impacts of loading JavaScript are extremely well known and common knowledge in a lot of the development community. But for the sake of this discussion, a few biggies: 1. a <script> tag (either as an external resource or as an inline script block) blocks all DOM processing after it, because the UA has to assume that a document.write() might occur inside it, which could alter how the UA needs to interpret the rest of the DOM. 2. Until the most recent generation of browsers (FF4, IE9), <script> tags would load in parallel to each other, but would still block downloading of subsequent resources (like images), again because of the assumption that something like a <base> tag may be `document.write()`en that would change the effective URL of such subsequent resource loadings. I guess these newest browsers simply abort and restart such loads if such a case occurs. That's debatable if that's a good behavior or not (good maybe for the UA, bad probably for the server bandwidth, which will deliver the whole resource regardless of an abort, etc). 3. There are well documented quirks with <script> and <link> tags in proximity to each other, where in certain cases one right after the other will cause blocking of the page rendering. There are many others. The bottom line is that for almost all of those performance concerns, dynamic script loading is the best available solution. But dynamic script loading is handcuffed in some ways without preloading. Thus, preloading would allow script loaders to solve a wider range of use-cases around these performance issues, and possibly solve them in more efficient ways than they currently are able to (without hacks). I cite the fact that dozens of popular script loaders use hacky "cache preloading" techniques as a way to get preloading. The fact that they do this, and that so many sites use them for that purpose, should prove that the (negative) performance of JavaScript loading demonstrates the de facto need for preloading. >> With a regular <script> tag, the UA waits for download and then waits >> for execution. The defer attribute helps by not blocking on download and >> deferring execution until later but preserves execution order; the async >> attribute helps by not blocking on download but does block on execution >> (the timing of which cannot be controlled) and does not preserve order. > > This doesn't seem to be a problem. Ummm.... "doesn't seem to be a problem"? Do you remember the whole async=false thread and all the rabbit trails it led to? Clearly, the order of scripts executing is still quite an issue on the broader web, and so just patently using something like <script async> DOES in fact create lots of "problems". >> 1. Preloading JS without execution >> (http://www.phpied.com/preload-cssjavascript-without-execution/) by >> Stoyan Stefanov, which describes how to download JavaScript without >> execution it, as a cache-warming technique. >> >> 2. ControlJS (http://stevesouders.com/controljs/) by Steve Souders, >> which extends Stoyan's model to allow on-demand execution of scripts. >> >> 3. Gmail putting JavaScript in comments and then parsing later >> (http://googlecode.blogspot.com/2009/09/gmail-for-mobile-html5-series-reducing.html) >> to enable download without execution and then execution on-demand. > > What problems do these solutions solve? Specifically, they solve this problem: I want to load two or more scripts that I don't control, from locations that aren't my own, in parallel (for performance), and I want them to execute in order..... BUT I want to control when that execution starts. Why? Because I want to load things early (to take advantage of keep-alive, etc), but I want to have execution happen later, so that the perception of my page loading quicker is preserved (script executions modifying the DOM can be quite time expensive and obvious). For instance, I want to download the code for rendering a complex calendar widget early, but I only want to run that calendar widget code to modify my DOM *when/if* the user expresses interest in seeing the calendar (maybe only 10% of users click the calendar icon button). It's not an option for me to host that code (as I don't have a world-wide CDN that can get the same shared-caching), nor is it an option for me to modify the code (since it's third party code). So, I can't just change that code to not run upon execution. I have to control when the script itself executes. >> For the purposes of this discussion, we are combining (but safely so, I >> believe) "execution" and "parsing", and saying that we want to be able >> to defer the "parse/execution" phase of script loading. > >I don't see any good reason to combine them. They seem emminently separable Wait... earlier in your message, you said: "There doesn't seem to be any need to treat them as separate steps". So which is it? Do you think we should talk about execution and parsing as a single step, or separately? FWIW, what I meant was that we (as proposers of the functionality) want to defer both parsing and execution, but not that we wanted to defer both equally. In other words, both are things that we want to defer, but they don't have to remain happening together. As I've already said earlier in this message, one of the conclusions of the Jan/Feb thread was that they in fact can be separable, and that it was sufficient (as far as I'm concerned) for parsing to simply be hinted to happen any time during the window between load-finish and execute-start, as this gives a greater likelihood that the UA won't do the parsing at an inopportune time (from the author's or user's perspective). The first major goal in my mind is still to accomplish the execution deferral (for scripts which can't otherwise be modified to do that directly). The second goal, which follows from the first, is that this allows a larger window of time between load-finish and execute-start as relief from the current system, which insists and requires that parsing happen "immediately" after load-finish, because (as stated many times), there are reasons you want to load a script much earlier than when you want to use it, like taking advantage of keep-alive, or (on mobile) taking advantage of when the mobile's radio is still transmitting (during initial page load), etc. >> Consider the controljs example in which the menu code does not load >> until it is clicked. There's no requirement that it run synchronously >> so it is acceptable for the script's execution to simply be scheduled in >> response to the click event. A non-prefetching browser would not be as >> "performant" but would still work. > > Why not just run the code sometime before it is needed, while the page is > idle? Why is it necessary to delay the load until the last possible > minute? What problem are we solving? Problem A can't be the problem being > solved here, since the execution takes a trivially short time compared to > the download and compiling. (see above -- the problem being solved here is NOT the deferral of parsing, but the deferral of execution, for a script that can't otherwise be modified to allow that to happen directly) >> The problem is that scripts loaded dynamically are not guaranteed to >> execute in any particular order. A mechanism for loading files in >> parallel but controlling (or enforcing) their execution order, is >> necessary. > > There are a number of solutions to this problem now (onload, defer/async, > .async, the careful definitions of insertion/execution order, etc). What > is wrong with them that we need more solutions? > >> For instance, if I have two groups of scripts ("A.js", "B.js" and >> "C.js") and ("D.js", "E.js", and "F.js"). Within each group, the order >> must be maintained, but the two groups are completely independent. As >> "async=false" is currently implemented, you cannot accomplish isolating >> the two groups of scripts from affecting each other. The "D,E,F" group >> will be forced to wait for the "A,B,C" group to finish executing. > > When does this happen? Do you have a concrete example? I don't have a concrete example of this in practice because the above is not currently possible (at least not without bad hacks). But I often find I want something like this to be possible: Group A: 1. jquery.js 2. jquery-ui.js 3. plugins.jquery.js 4. plugin init code Group B: 1. ga.js 2. google-analytics init code Group C: 1. twitter-api .js file(s) 2. twitter init code Within these 3 groups, execution order must be preserved. The groups themselves are completely independent of each other, however. I want all files to load in parallel (for performance), but I want each group to execute as soon as that group is ready. In other words, I don't want Group B to wait on A, if B is ready to go before A. Similarly, I don't want C to wait on A or B, if it's ready earlier. This scenario is currently impossible (or nearly so, without hacks). In some (spec-conforming) browsers, I can use async=false on all those script elements, and their order will be preserved. But that means that also it will force Group C to wait for B, and group B to wait for A, because `async=false` only specifies one global queue for such scripts. Preloading would let me load all of these scripts in parallel, but execute any group as soon as I was notified that all the scripts in that group were finished loading. > Note that there are multiple solutions to this already: > > - put A,B,C into one file and D,E,F into one file. Already covered numerous times why this isn't sufficient... because I don't control all of the files, nor do I host them (they're on performance-optimized CDNs). > - write the scripts so that they don't rely on each other during > execution, but instead expose a function that you can call when you > want, e.g. when they are all loaded. (ditto above) > - run the scripts in two iframes. Are you serious? That may be the most hacky of all suggested solutions to date. The scripts need to run in my main page, not in a separate iframe. AT BEST, this would be the hacky "cache preloading" that simply gets the scripts into the cache but basically ignores their side effects (in a hidden iframe). But as stated above, cache-preloading is wholly insufficient for our needs. > - create <script> elements ahead of time and insert then in order, > allowing the browser to download and compile them in parallel, but > insert them in the order you need them, when they are ready, using > onload to trigger B from A and C from B, etc. What do you mean: "ahead of time" and "when they are ready"? Are you assuming the presence of a preloading mechanism (and the signals of such preloading completing) that we are proposing? That's certainly *begging the question*. As current tech stands (IE not withstanding), I cannot request scripts in parallel, but control in what order they are executed using onload chaining, because the scripts won't be fetched until they are added to the DOM, and once they are in the DOM, they will all execute themselves as soon as each finishes, regardless of `onload`. The order of execution will depend on the browser type, and if async=false was used or not. But `onload` chaining as you suggest is a nonsense/non-functioning scenario if preloading doesn't exist (which it doesn't yet, except for IE). >> 2. Another plausible use-case that occurs to me is loading two >> overlapping plugins (like for jQuery, for instance). The author may have >> a simple calendar widget and a much more complex calendar widget, and >> the two may conflict or overlap in such a way that only one should be >> executed. But for speed of response, the author may want to "preload" >> both plugins and have them waiting on hand, and depending on what action >> the user takes (or the state of data from an Ajax request), may then >> decide at run-time which of the two plugins to execute. > > Do you have a page that tries to do that kind of thing? I don't think I've > ever come across this kind of thing. The reason I brought it up is I've got two different sites where I've wanted to do this (or at least explore if the performance savings would be as big as I think they would be) but it's really almost impossible (or implausible) to do such a thing thus far. It would be trivial to do with the preload functionality being suggested. > Incidentally, just as a parting note: a lot of e-mails on this thread > seemed concerned about how hard something was to spec, for example > preferring solutions grounded in existing spec text In the case of two proposals which both address the use-case, I think that preference should absolutely be given to the one which has the least change to the spec, because that proposal has the least chance for unintended side effects (both in the spec and in spec-conforming implementations). The implications I made of the benefits of using existing spec precedent had nothing to do with whether or not you (Ian) would be more inclined if it were "less work". I was entirely talking about the surface of risk being smaller the fewer the changes that are made. And I still insist that, all other things being equal, that's a perfectly valid assertion for making a decision, in a case where the only other differences in effect are subjective opinion. --Kyle
Received on Monday, 30 May 2011 12:52:17 UTC