42

This question is sort of a tangent to Which browsers support <script async="async" />?.

I've seen a few scripts lately that do something like this:

var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = 'http://www.example.com/script.js';
document.getElementsByTagName('head')[0].appendChild(s);

This is a common way to add a script to the DOM dynamically, which, IIRC from Steve Souders's book "Even Faster Web Sites," prompts all modern browsers to load the script asynchronously (i.e., not blocking page rendering or downloading of subsequent assets).

If I'm correct in that, does the s.async = true statement have any use? Wouldn't it be redundant, even for the browser(s) that support that property, since dynamically appended a script should already trigger asynchronous downloading?

5 Answers 5

25

The question is does s.async = true have a use for dynamically inserted scripts, or are these loaded asynchronously already. The answer is they aren't loaded asynchronously in all browsers, as explained here (thanks to Markus Olsson for the link)

script-inserted scripts execute asynchronously in IE and WebKit, but synchronously in Opera and pre-4.0 Firefox. In Firefox 4.0, the async DOM property defaults to true for script-created scripts, so the default behavior matches the behavior of IE and WebKit.

In browsers that support async but don't already default to asynchronous loading (for example, Firefox 3.6), async = true makes a difference.

(The above link confirms that async is supported in Gecko 1.9.2, the layout engine used by Firefox 3.6)

2
  • Would be interesting with an answer update concerning recent browser versions. I currently use s.setAttribute("async", "");. Do you know if that works?
    – Gruber
    Commented Sep 18, 2015 at 10:53
  • 1
    Is there a badge for "come back 6 years later to accept an answer that's been correct all along, whilst simultaneously causing the newly-accepted answer to contradict itself because it refers to the accepted answer as wrong, when it has just become the correct answer itself?"
    – Bungle
    Commented Apr 8, 2017 at 6:50
23

The specification (now) dictates that a script element that isn't parser-inserted is async; the async property is irrelevant to non-parser-inserted script elements:

The third is a flag indicating whether the element will "force-async". Initially, script elements must have this flag set. It is unset by the HTML parser and the XML parser on script elements they insert. In addition, whenever a script element whose "force-async" flag is set has a async content attribute added, the element's "force-async" flag must be unset.

Having the async content attribute does, of course, mean the script would be executed asynchronously. The spec language seems to leave an opportunity to force synchronous execution of the script (by setting the attribute and then removing it), but in practice that does not work and is probably just a bit of vagueness in the spec. Non-parser-inserted script elements are async.

This specified behavior is what IE and Chrome have always done, Firefox has done for years, and current Opera also does (I have no idea when it changed from the old behavior in the answer linked above).

It's easily tested:

var script = document.createElement("script");
script.src = "script.js";
console.log("a");
document.body.appendChild(script);
console.log("b");

...with script.js being

console.log("script loaded");

...will log

a
b
script loaded
0
3

Interesting - I think it turns out that I was wrong in my assumptions.

Based on this thread in the jQuery developers' forum:

http://forum.jquery.com/topic/jquery-ajax-async-vs-html5-script-async

it looks like the async property has been discovered to have an effect on dynamically-appended scripts, at least in Firefox (and potentially Opera, though it doesn't yet support the property).

The forum thread also cites Google's asynchronous tracking code implementation, which, although it appears to make use of the async property in the appropriate context, actually appears to get the syntax wrong. Google uses:

ga.async = true;

when apparently that doesn't work; the proper method would be to use either:

ga.async = 'async';

or

ga.setAttribute('async', 'async');

So, based on my current understanding, not all browsers will actually execute dynamically-appended scripts immediately upon their insertion into the DOM in all cases; Firefox (and eventually Opera) will need the async property to be set to ensure that this always happens.

More info on Firefox's implementation of async here:

https://bugzilla.mozilla.org/show_bug.cgi?id=503481

4
  • Very interesting thread over at jQuery forums. Guess my google fu wasn't strong enough to find it ;) Thanks! Commented Aug 11, 2010 at 11:01
  • 3
    I don't think this is correct. typeof ga.async is "boolean", and even after you set it to 'async' you'll find that ga.async has a value of true (due to type coercion). I checked this in FF 3.6 Commented Mar 1, 2011 at 21:20
  • I believe the person who said it wasn't working in the jQuery was misunderstanding what the async attribute should do, as some other posters pointed out. By the way, note that ga.async = true results in HTML like <script type="text/javascript" src="foo.js" async=""> (at least as viewed in Firebug) but as far as I can tell what matters is the presence of the async attribute, not the string that follows it. Anyway, ga.async = "async" results in the same thing. Commented Mar 1, 2011 at 21:25
  • Correcting my last comment, apparently if the async attribute is given a value in the markup it should either be "async" or the empty string. But when setting it in the DOM (as in ga.async =) async is a boolean, so you should set it to true or false. As I said, the fact that ga.async = "async" produces the same result is just because "async" is coerced to true. Commented Mar 1, 2011 at 22:37
1

I believe you're correct.

In Steve's own examples he does not set the async attribute before attaching the script tag to the head element.

My understanding of the async atttribute is that it's a way of signaling to the browser that you don't intend to manipulate the page by using document.write so that it can continue rendering instead of halting to load the script. See the documentation for the script element at mdc which contains a bit more on the document.write/async issues.

Note that with your technique you shouldn't use document.write anyway since you've got no way of knowing where in the page lifetime your script will be loaded.

1
  • Markus - great answer, and I appreciate your contribution! I looked into this further, and made some discoveries - please read the answer I just added.
    – Bungle
    Commented Aug 10, 2010 at 3:49
1

Setting the "async" attribute can be done with:

element.setAttribute("async","")
element.setAttribute("async","anystring")

see: https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute#examples

Removing the "async" attribute can be done with:

element.removeAttribute("async")
1
  • As far as I understood, this was not the OPs question. It is not asked, how to add the async property but if it is useful to add it. Commented Mar 7, 2023 at 23:28

Not the answer you're looking for? Browse other questions tagged or ask your own question.