Bug 21074 - Need ability to load scripts without blocking onload
Need ability to load scripts without blocking onload
Status: RESOLVED FIXED
Product: HTML WG
Classification: Unclassified
Component: HTML5 spec
unspecified
All All
: P2 enhancement
: ---
Assigned To: Robin Berjon
HTML WG Bugzilla archive list
http://www.lognormal.com/blog/2012/12...
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2013-02-21 16:15 UTC by Philip Tellis
Modified: 2014-12-20 10:53 UTC (History)
8 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Philip Tellis 2013-02-21 16:15:29 UTC
The URL describes this in detail, but I'll describe a summary here.

Current Situation:

We include scripts in an HTML document using the <script> tag:

<script src="script-url" type="text/javascript"></script>

In this case, parsing and rendering of the document blocks until the script has been downloaded, parsed and executed since the script might change the document using document.write.

If the script does not use document.write, the developer can use the async attribute to tell the browser that it can continue loading, parsing and rendering the page in parallel with the downloading, parsing and execution of the script:

<script async src="script-url" type="text/javascript"></script>

However, this script will still block the onload event (not clear in the spec, but all implementations appear to do this).


Required Enhancement:

We should either add a new attribute: "nonblocking", or add a new attribute value for the async attribute: async="nonblocking".  It would work as follows:

<script async="nonblocking" src="script-url" type="text/javascript"></script>

This provides a hint to the user agent that it should start downloading, parsing and executing as soon as possible but it should not block the onload event (or any other event) of the containing document waiting for this script to download, parse and execute.

This should also be usable in dynamically injected script nodes.

User Agents that treat async as a boolean attribute will fall back to the current model.

Why do we need this?

Third party scripts are included in websites all over the Web.  If one of these third party servers becomes unresponsive (eg: DNS failure, host timeout, etc.), this will block the onload event on all sites that include the third party script even if the async attribute is used.

Since many sites perform some amount of page setup tasks in the onload event handler, this could block these tasks indefinitely depending on timeout values.

The only option now available is the iframe hack described in the attached URL.
Comment 1 Philip Tellis 2013-02-21 16:16:33 UTC
It would also be nice to have this for iframes so we do not block onload waiting for ads to load.
Comment 2 Travis Leithead [MSFT] 2013-02-21 16:25:33 UTC
Another alternative to simply telling the script not to block the load event, is to instead allow the developer to specify the timeout value for a script (since you would have to opt-in to a new attribute 'noblocking' anyway--I expect that problematic script libraries would need to be known a-priori so this would work...).

For example:
<script src="script-url" async timout="2s"></script>

Would still block the load event for up to 2 seconds in the worst-case and would then abort the connection and fire the load event.

Thoughts?
Comment 3 Philip Tellis 2013-02-21 16:33:56 UTC
The timeout has a use case, but I don't think it is a replacement for nonblocking.

for example, you may not want to abort the download.  you might still want to let it load up whenever it does.

Consider a server that generally responds in 50ms, but in 1% of cases takes more than 5 seconds to respond.  The user will most likely still be on your page 5 seconds after it starts loading, so the script load will complete, and can still do what it needs to (eg: stats gathering, or a widget at the bottom of the page).

Blocking onload for 2 seconds is also not acceptable because we may be blocking execution of scripts for something that really does not care about the onload event.
Comment 4 Travis Leithead [MSFT] 2013-02-21 16:38:06 UTC
I wonder then if we can't just integrate the semantics of non-blocking into the existing async attribute?

Are there specific use cases where you want async-but-blocking?
Comment 5 Philip Tellis 2013-02-21 16:57:23 UTC
Possibly in the case where an onload handler depends on functionality provided by the script.
Comment 6 Lee Kowalkowski 2013-02-21 21:58:11 UTC
(In reply to comment #0)
> The only option now available is the iframe hack described in the attached
> URL.

...or just not use the onload event at all!  I rarely use it, for good reason - it's always too late, and it's not just other scripts, it's everything!  

Often I'm halfway through filling out a form when the onload event causes a script to put focus back into the first field as I'm typing.  Infuriating!  Especially if it's the password I'm currently entering, and now my password is visible.  I just scream "Why are they using the onload event?!  Why would ANYBODY!!!", haha, really, I do!  Too often.

Of course the problem is the onload event can be delayed by any resources, not just scripts.

Whilst "nonblocking" sounds feasible, I don't think I will be persuaded to use it, because it still won't enable me to use the onload event satisfactorily.  

If the problem really is that the onload event could sometimes take forever, then best not to use it for anything critical to the user.

There is a DOMContentLoaded event which looks more appropriate.
Comment 7 Philip Tellis 2013-02-22 05:05:47 UTC
@Lee this isn't just to make sure the onload event handler fires on time.  Onload is also used as a proxy to determine when a page is ready from a statistics gathering perspective.  There are also users who won't start interacting with a page until the spinner stops spinning, which happens on onload.

Regarding DOMContentLoaded, it still doesn't guarantee that scripts loaded with the async attribute have finished downloading and executing, so you cannot depend on any of the functionality they provide.
Comment 8 Lee Kowalkowski 2013-02-22 10:32:09 UTC
(In reply to comment #7)
> Onload is also used as a proxy to determine when a page is ready from a
> statistics gathering perspective.

If gathering statistics isn't critical to the user, then using the onload event might be OK.  If gathering statistics for a page hit where the user didn't wait for onload is desirable, then don't wait for the onload event to gather the statistics.

Perhaps the fact that the user didn't wait for onload is a useful metric itself, perhaps the only useful statistic that can be gathered using the onload event, is the page load time.

> There are also users who won't start
> interacting with a page until the spinner stops spinning, which happens on
> onload.

I can't find any supporting evidence of the severity of this user phenomenon, no doubt there are some users with that habit, it's not an observation I've made very often, new users tend not to understand the spinner.  I know that young children don't do this, as soon as what they want is visible, they will try to use it.

I do remember it being necessary to wait until the page has finished loading when using some specific badly-implemented sites though (i.e. pages that don't even work properly if you interact with them too soon).  Perhaps such users are doing this from such experience, applying the behaviour as a rule to use all sites by, kind of like superstition.  For sure, the onload event is being used inappropriately on such sites.

Perhaps what we need in the HTML5 reference is a warning on the onload event that it is probably not as useful as the author might expect, given inherent uncertainty with networks.

> Regarding DOMContentLoaded, it still doesn't guarantee that scripts loaded
> with the async attribute have finished downloading and executing, so you
> cannot depend on any of the functionality they provide.

You should probably not use the async attribute for functionality the user will depend on though, and you should probably not have inter-script dependencies loading asynchronously without building a mechanism to allow the dependency to be late (e.g. polling).  

The async attribute is best suited for non-critical scripts (e.g. scripts that will progressively enhance something that is already functional).
Comment 9 Kyle Simpson 2013-02-24 03:29:23 UTC
I personally don't understand the need to avoid the `onload` blocking (and I happen to have plenty of experience in this area, as the author of LABjs script loader). I think the far bigger culprit is blocking the DOMContentLoaded event, and thankfully all the `async` and dynamic-script-element approaches take care of that part.

That having been said, even if I don't see the need for this, PLEASE do not piggyback on, and/or change, in any way, how `async` works (as I saw suggested in this thread). There are many, MANY script loaders, mine included, which rely on very specific behavior of `async`. It's a very tenuous and delicate balance we're currently in, where it barely works, but works just well enough.

On a side note, I doubt this request is going to get very far, because I have been trying to get another helpful change (script preloading: https://www.w3.org/Bugs/Public/show_bug.cgi?id=14194) made to the script loading behaviors of the browser for well over 2 years now, and keep getting stonewalled on it, mostly for the "just tell authors to do something different" excuse. I think the same fate is likely here, that they'll just say "why can't you just tell authors not to load stuff before `onload` if they don't want to block `onload`... wait until after it passes to start the loading."

I know, and you know, that's suboptimal compared to what you're asking for itself, but it's the same reasoning as what has blocked my requests for ages.
Comment 10 Yoav Weiss 2013-02-25 09:29:49 UTC
I support adding a mechanism that avoids blocking of the "onload" event by scripts, but as Kyle mentioned, this is not the only use-case that is not currently covered by `async` and `defer`.
I believe that another use-case can be "Loading scripts after onload" in order to load scripts of some added value, but ones which we don't want to intervene with the page's load time. While this can be easily done using scripts, having a declarative way to do that would be easier & cleaner. Also, in some cases, it avoids the use of inline scripts, which is complicated when using CSP.

Yet another use case may be loading of scripts according to `media`, since some scripts may be required only for certain layouts.

I suggest to gather up all the use-cases and see if we can solve all of them under a single solution.

AFAIK, the list includes:
* Loading scripts without blocking onload
* Loading scripts, but avoiding their execution
* Loading scripts after onload
* Loading scripts according to `media`

Are there any use-cases I'm missing?

Yoav