Repository navigation
script[defer] doesn't work in IE<=9 #42
Description
Activity
kyle added....
To answer @paulirish's earlier question (https://github.com/paulirish/html5-boilerplate/issues/28#issuecomment-1765361) about defer quirks, look at how "DOMContentLoaded" behaves across IE, Chrome, and Firefox in the defer test.
In IE9 and Chrome15, the DOMContentLoaded event is held up (blocked) and not fired until after the scripts run. In FF, however, the DOMContentLoaded event is not held up, it fires right away, and the scripts start executing after it. That's a giant inconsistency across modern browsers, and one of the reasons why I don't think defer is sufficient.
To give more context to the above list of
deferissues:deferdoesn't have any meaning in dynamic script loading. But it doesn't need to, because of the new "ordered async" (async=false) that IS spec'd and now in almost all browsers' current releases. What's confusing though is that you have to usedeferwhen you're dealing with markup, andasync=falsewhen you're dynamically creating script elements. The latter would make you assume you could/should useasyncin markup, but that's not going to work because order is not preserved -- unless of course you happen to not care about order.- this is now proven (partially documented) by this video: http://www.screenr.com/icxs To save you from having to watch it, though, IE9 and Chrome15 both block the
DOMContentLoadedevent (aka, "DOM-ready") until after all thedeferscripts finish, whereas FF8(nightly) does not block the event. I'm willing to bet there are other browsers which fall on both sides of that issue, as well, as the spec seems a bit confusing on this particular point (at least in my reading). - It seems from some older blog posts that at one point, inline script blocks could have
deferset on them, and browsers would respect that. http://hacks.mozilla.org/2009/06/defer/ However, as that video above clearly illustrates, none of the current browsers respect that, and in fact, reading the spec,deferis NOT defined for inline script blocks. That makes it uber-difficult to convert an existing set of script tags (some external, some inline) to usedefer, if those inline blocks are relying on ordering (almost always they are). - I don't have much evidence of this, but I know a guy who's done a bunch on this, and I'll ping him to get some more specifics. I stay far the hell away from
document.write(), but some unfortunate souls have to deal with that reality (aka, "nightmare").
I made a test which seems to confirm the following:
In FF, however, the DOMContentLoaded event is not held up, it fires right away, and the scripts start executing after it. That's a giant inconsistency across modern browsers, and one of the reasons why I don't think defer is sufficient.
http://dl.dropbox.com/u/513327/domload_defer.html (load and reload it in Firefox 5 and then load in Chrome)
Chrome 12 results:
expected: number; got: number;
Firefox 6, 5, 4, 3.6 results:expected: number; got: undefined;
Firefox 3.5, 3.0 results:expected: number; got: number;Update: I removed the Cuzillion tests on visual rendering blocking because they were invalid.
Isn't blocking the visual rendering only supposed to occur with non-
defered scripts? What would be the advantage ofdeferthen? I'd say all is well with how FF 3.5+ and Safari handle it. Safari 4 and sorts blocking may just be indication that they don't recognize adefer-attribute yet.In regards to
DOMContentLoadedevent being triggered too early, maybe the following manualDOMContentLoadedtriggering technique may be of interest for a fix: http://stackoverflow.com/questions/942921/lazy-loading-the-addthis-script-or-lazy-loading-external-js-content-dependent-oif( document.createEvent ) { var evt = document.createEvent("MutationEvents"); evt.initMutationEvent("DOMContentLoaded", true, true, document, "", "", "", 0); document.dispatchEvent(evt); }
In regards to DOMContentLoaded event being triggered too early, maybe the following manual DOMContentLoaded triggering technique may be of interest for a fix
I think that might cause problems with some handlers as it's generally assumed
DOMContentLoadedis only fired once.FWIW:
[22:36] <matjas> is there a point in using @defer when you only use a single <script> and it’s at the bottom, right before </body>? [22:36] <Hixie> not really [22:38] <matjas> not really or not at all? [22:38] <matjas> what is the point? [22:39] <Hixie> there's no point that i can think of [22:39] <Ms2ger> Being fancy! :) [22:39] <Hixie> there are some subtle minor differences, but nothing useful i don't thinkAre the logical next steps to:
a) define and agree on the test cases?
b) define and agree on the testing methodology?
c) create solid test pages
d) do the testingI ran your DCL test page (http://dl.dropbox.com/u/513327/domload_defer.html) in IE9:
expected: number; got: number;The question is: What is our goal here (in regards to H5BP)? Upgrading all scripts which are already aligned at the document's end with
defer? Even if we wouldn't have aDOMContentLoadeddiscrepancy between browsers we would not gain anything performance-wise.deferreally makes sense when you have like a stubborn CMS that cannot queue scripts for an insertion at the very end. But then again, you cannot generally auto-deferall scripts that you come across as they might contain adocument.writeor they are accompanied by some (officially) non-deferable inline-script. So the main problem is that even if all browsers would follow one standard, it will never be a no-brainer solution.What we could do is do some tests just for fun and curiosity (which might be reason enough ;)
Isn't the visual rendering blocking/non-blocking that @jdalton reported expected? The report HTML on the Cuzillion page comes after the external script. So doesn't it make sense that it would be blocked without
deferand not blocked withdefer?@robflaherty Good point. This:
…appears after the last
<script>in the test page HTML, so it’s not really a test case of<script defer src=foo></body>.If the
deferattribute were defined that it should push the scripts to start executing immediately after it fired theDOMContentLoadedevent (like it does in FF), thendeferwould be useful even at the end of the body, because drastically speeding up DOM-ready is quite effective in improving the "perceived performance" of a site, which makes users think the site actually did load quicker, even if it loaded slower overall.As it stands,
deferseems somewhat more useful in FF than in IE9 and Chrome15.If "defer" is made the default, will developers get confused that their inline JS is processed before the deferred (external) scripts?
http://www.artzstudio.com/files/Boot/test/benchmarks/script.defer.html
Most sites have a need for inline JS, for example Google Analytics code, page specific initialization, etc.
- update looks like Cuzillion says this should work... :/
http://stevesouders.com/cuzillion/?c0=hj1hfft2_0_f&c1=hj1hfft2_0_f&c2=hb0hfff0_0_f&t=1313075137650
- update looks like Cuzillion says this should work... :/
Couple of other points... it may be worth noting that stylesheet downloading blocks
DOMContentLoadedonly if the stylesheet is followed by scripts. Addingdeferchanges this and causesDOMContentLoadedto fire before the stylesheet has finished downloading. Probably not a common scenario but I thought I'd mention it.Example: http://stevesouders.com/cuzillion/?c0=hc1hfff2_0_f&c1=bj1hfft1_0_f&t=1313073628
Another thing to keep in mind when testing is WebKit's PreloadScanner, which prefetches scripts and runs in just about every real-world scenario. In more cases it's surely tangential but there may be some wacky test cases where it affects results.
37 remaining items
Didn't you just write this one earlier in the thread?
http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#attr-script-defer
"The defer and async attributes must not be specified if the src attribute is not present."Any syncronicity between a defer+src script with an inline script (ie, something running a JQuery function) is coincidential, and undefined browser behavior.
I tend to think of inline scripts (as in, inline between pieces of content, not a single inline script in head that configures your libraries) as archaic deprecated behavior, like conditional HTML comments; , so I'm not surprised that having them in place breaks newer script-loading features.
Reacted by Mikko RantalainenHello,
what is the difference between <script async=''async'' & <script async=''
Reacted by Aicke SchulzNone, really...they're both syntactically accepted because some HTML-writing programs don't follow the Boolean nature of attributes, and because it's required for valid XML.
Attributes like "async" or "disabled" don't actually require an equals sign. It's valid to write <script async> or . Anything inside the equals is pretty much ignored. When checking for those Booleans, JS code usually checks "element.hasAttribute(x)" rather than "element.getAttribute()", so even if it registers as an empty string, it will turn out true.
For posterity sake, let's not clutter up this thread with general support inquiries about web platform features. Please take this discussion to stackoverflow or some other forum where it's more appropriate, and remove the messages here.
Reacted by Paul IrishAn user reported the suggested fix didn't work for him. If other users could confirm this, the original post should be edited so that people who land on it are not misled ;)
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This issue has been automatically closed because it has not had recent activity. Thank you for your contributions.

(Edited 2012.03.01)
TL;DR: don't use
deferfor external scripts that can depend on eachother if you need IE <= 9 supportThere is a bug in IE<=9 (confirmed, below, by an IE engineer) where if you have two scripts such as...
And the first script modifies the dom with
appendChild,innerHTML, (etc.), the second script can start executing before the first one has finished. Thus, a dependency between the two will break.The details of this limitation begin at this comment
This essentially means that
script[defer]cannot be used in most cases unless you have dropped IE8 and IE9 support. If, however, you can UA sniff to serve script[defer] to all browsers except IE6-9, that will net you large performance wins.Steve Souders indicated there may be a hack of inserting an empty
<script></script>tag between the two tags that may address this problem. Research to be done…original post follows:
# comprehensive research and article on script @defer
@deferscripts execute when the browser gets around to them, but they execute in order. this is awesome for performance.it's also awesome that it's been in IE since IE5.
but, we're lacking a little bit of comprehensive research on this..
kyle simpson thinks there may be some edge case issues with defer... from this h5bp thread...
it'd be excellent to get a great summary of the full story across browsers and these issues so we can use defer confidently.
see also:
- @aaronpeters @Schepp