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 12049 - Script defer/async attributed have no realistic usage scenario
Summary: Script defer/async attributed have no realistic usage scenario
Alias: None
Product: HTML WG
Classification: Unclassified
Component: LC1 HTML5 spec (show other bugs)
Version: unspecified
Hardware: All All
: P2 major
Target Milestone: ---
Assignee: Ian 'Hixie' Hickson
QA Contact: HTML WG Bugzilla archive list
Depends on:
Reported: 2011-02-12 21:44 UTC by silvio.ventres
Modified: 2011-08-04 05:13 UTC (History)
6 users (show)

See Also:


Description silvio.ventres 2011-02-12 21:44:43 UTC
The point of defer'ing or async'ing a script is to allow other content to load without blocking waiting for the subject script to load.
But the information regarding which script load will be slowest is not available at time of web page authoring, especially if scripts are not hosted at the same server as the webpage itself.

The effect is that if a web developer wants to make the web page "faster" and more interactive, seen especially in lower initial paint latency, he should use defer/async wherever possible. Given that the dependency tracking between scripts is not an easy problem for an average user to solve, and that, while testing with local/unloaded hosting facilities, the low latencies will mask any dependency problems, the user does not have an easy way to determine if some script would be hurt by deferring or even asyncing it. This leads to use of defer/async everywhere, which might break the page layout when some performance problem with hosting of any resource arises.

Thus, propose to add into the standard that the only attribute regarding execution order to be user-specified should be "strict" or "strict-order". In all other cases, browser should do the guesswork determining which scripts can be deferred, and tracking dependencies, deferring slow-loading scripts, especially if hosted in different domain-origin. If the slow-loading script should ever finish loading, the browser should then examine the script and determine whether the whole page should be reparsed.

This will allow the browser to provide low-latency initial paints for all webpages, except those that explicitly specify the "strict-order" attribute, knowing full well the performance impact of such change.

Make the mostly-clueless majority of modern web developers default to "fast and corrected automagically" and the clueful minority able to choose "possibly slower and overriding the automagic" if they wish to. Otherwise you risk the mostly-clueless majority to default to "fast and incorrect" which browser-developers will then have to add quirks to mitigate.
Comment 1 silvio.ventres 2011-02-12 23:42:44 UTC
Found an example of a workaround that works in most browsers, except webkit nightly and ff4beta that implement defer/async as specified in the HTML spec:

As can be seen in the API, the default is "load whenever possible", and the only user-specified case is "wait()" which acts to strictly order the execution, like the "strict-order" proposed.
Comment 2 silvio.ventres 2011-02-13 00:03:18 UTC
Of course, head.js and control.js do the same thing.
What needs to be seen here is that those are workarounds, that users were forced to create because they want this behaviour from the browser.

A webpage should not be required to use complex script-loading addons like head/control/Lab-js. Instead, the default should be to optimistically defer as much as possible and fix the problems when they occur.

These loaders show that users do care about the initial paint latency.
So why not make the latency universally-low and only restrict execution order for people that really require it ?
Comment 3 silvio.ventres 2011-02-13 00:33:09 UTC
Indeed, it looks like the "strict-order" attribute exists already, in "async=false" attribute.

What needs to be changed now is the default behaviour: default should be all-async with later fixes, with async=false for strict execution order control.
There shouldn't be a need to enter async/defer attributes for the users to gain performance.

The default should be high performance async/defer automatic guessing.
Comment 4 Kyle Simpson 2011-02-13 14:29:36 UTC
If you're suggesting that the default behavior of script tags in markup change from not-async to async, I think that's an impossible change to request. Far too many websites expect that scripts execute in the order they appear in the DOM. This would cause enormous web-compat issues with millions of sites. By definition, when `async` is turned on, scripts execute in "as-soon-as-possible" order. 

BTW, the "async=false" thing, which I was the one primarily who pushed that proposal, that's not about script default behavior with markup script elements. It's about the default behavior of script-created script elements. An implicit assumption was made there, mostly for web-compat reasons, that if people do script tags in markup, by default they want ordered execution, and if they do them with a script loader, by default they want un-ordered execution. And we gave them the ability to opt-out of the default behavior in either case.

If you're suggesting that the default behavior of script tags in markup change from not-defer to defer, this has less of a potential for breaking web-compat, but is still a really bad idea in my opinion.

Before I explain *why* I think it's a bad idea, though... how would you suggest that a web author opt a markup script element out of `defer` (or `async`) behavior? In markup, you *cannot* do "defer=false" (boolean attributes in HTML don't work like that). So, you'd have to invent a new attribute like "noDefer" or "noAsync". Is that what you're thinking?


Regardless, you're essentially saying that most people want their scripts to defer. But that's not true. A lot of websites use heavy amounts of JavaScript to build out the UI of their site/application, and they *want* the blocking behavior of their script loading because they don't have any content they want to show to the user until the JavaScript has had a chance to attach and build out the presentation.

In all cases, I disagree completely with the notion that less control over such behavior is appropriate -- in fact, the opposite, I'm lobbying for more controls. I also think it's impossible to assert that the long-standing default is now irrelevant. Web authors have the ability to opt-in to be more performant behavior, assuming they understand the UX implications. 

I don't think we should assume that every site on the net already has that figured out yet, though. There's still LOTS of work to be done in that area. This proposal may be more appropriate 6-8 years from now, but at the moment, I think it's completely the wrong thing for today's (and tomorrow's) web.

Also, one last critical thing this proposal would break on millions of sites: DOM-ready detection. Libraries like jQuery rely on the fact that it was loaded before DOM-ready (so that the library itself can detect DOM-ready), or the library has to rely on some hacky fallbacks (depending on different browsers) to try and detect if DOM-ready has already passed. BUT, while jQuery has this logic in it, several other major JavaScript libraries (like Prototype and Dojo) do *not* have the same "safe DOM-ready" detection logic, and would thus completely die if loaded via a script with defer set on. We simply cannot expect millions of sites using such libraries to change their script tags to somehow opt out of defer.

There's millions of sites out there who rely on the script loading of script tags in markup to block the page's DOM-ready, so that when DOM-ready fires, they can assume that all scripts are loaded. I don't think this is a GOOD practice to make that assumption (in fact, I think it's a terrible anti-pattern). But nonetheless, it's true on the vast majority of sites (especially those using jQuery, where that pattern is most prevalent).

Bottom line: I think it's an impossible task (any time soon enough to be still in my career) to change such a fundamental default. Even if the spec did it, I think the browsers would universally push back because of such fears about compat. The burden would be on you to prove that 99.9% of sites wouldn't break with your proposal, and I think that's a pretty tough task to do.
Comment 5 silvio.ventres 2011-02-23 20:03:39 UTC
After giving the idea some more thought, it became apparent that there is a solution to the script dependency tracking.

It's quite simple, really.

Again, assuming most users don't have a clue regarding script order, and don't really have any means to do it correctly,
especially with scripts that are externally-sourced and thus have dynamic loading performance, the solution is to assume
all scripts are deferrable, unless they depend on a non-defined function evokation.

The engine should execute scripts as they arrive from the network, in whatever random order that is, until an undefined 
function call is encountered. At that point the scenarios can be different. Here are two:

First scenario:
  The browser engine saves a snapshot of the DOM before script initial run. After encountering the undefined function,
the changes are rolled back and the script is pushed to the end of the "deferred" queue, and flagged so it can only be
executed after at least one different script is executed. In case the queue is empty, the function is really considered
undefined and an error exception is triggered.

First scenario Optimization:
  The undefined function/functions are saved in an "undefined_functions" hash/table and the script retried execution only
when all functions have been provided definitions or there are no more scripts to run.

Second scenario:
  The browser engine launches script execution in a separate sleep-able thread. After encountering the undefined function
the engine puts the executing script to sleep and sets its wake time as in first scenario - either executing after another
script or when the function symbols have been resolved.

Whether it's easier to do DOM snapshots, analysis and rollbacks (with alert() workarounds) or multithread sleep/wake is left to the browser developers to choose. Additional implementation-specific solutions might exist too.

This provides ability for the web browser to "process" and provide the user an output given "incomplete" data.
Given that most of the time this "incomplete" data are externally-sourced ad or tracker scripts, this solution should
solve the problem.

For comparison, on and other alexa-2000 sites setting external-source scripts to defer unconditionally
halves the first-paint time on WebKit implementation without causing any bad renders. Although that has theoretical
problems, the above algorithm should be 100% compliant with the current standard.

Thus, advise to use the above algorithm and move the script deferability decision from webdev to the browser, where it belongs.
Comment 6 Aryeh Gregor 2011-02-23 23:56:09 UTC
(In reply to comment #5)
> Again, assuming most users don't have a clue regarding script order, and don't
> really have any means to do it correctly,
> especially with scripts that are externally-sourced and thus have dynamic
> loading performance, the solution is to assume
> all scripts are deferrable, unless they depend on a non-defined function
> evokation.

There are zillions of ways JavaScript files can depend on each other other than function calls.  For instance, one might set a variable that the other one later checks.  One might modify the state of the page in a way a later script depends on, like changing some existing property of document or window or modifying the DOM.  There's no way to detect this kind of dependency if you run the scripts out of order.
Comment 7 Ian 'Hixie' Hickson 2011-05-05 06:46:28 UTC
EDITOR'S RESPONSE: This is an Editor's Response to your comment. If you are satisfied with this response, please change the state of this bug to CLOSED. If you have additional information and would like the editor to reconsider, please reopen this bug. If you would like to escalate the issue to the full HTML Working Group, please add the TrackerRequest keyword to this bug, and suggest title and text for the tracker issue; or you may create a tracker issue yourself, if you are able to do so. For more details, see this document:

Status: Rejected
Change Description: no spec change
Rationale: The premise of this bug is false: not all scripts depend on each other. The primary use case for async="" is a third-party analytics script or ad script, which can be completely independent of all other scripts on the page.

(If there is another problem, please file a separate bug just describing that problem.)
Comment 8 Michael[tm] Smith 2011-08-04 05:13:50 UTC
mass-move component to LC1