HTML5’s async Script Attribute
One of the big reasons I'me excited about HMTL5 is that features are being implemented that have been long overdue. We've been using placeholders forever but we've needed to use JavaScript to do it. We've been making entire blocks clickable like links but we've needed to use JavaScript to do it. WebKit recently implemented HTML5's async
attribute for SCRIPT tags. We've been accomplishing this task with a variety of JavaScript hacks but this new attribute will allow us to prevent blocking in an easy way.
async - The HTML
As I mentioned above, it's as easy as adding an attribute:
<script async src="siteScript.js" onload="myInit()"></script>
The truth is that if you write your JavaScript effectively, you'll use the async
attribute to 90% of your SCRIPT elements.
defer - The HTML
Safari has also added a defer
attribute:
<script defer src="siteScript.js" onload="myInit()"></script>
Very similar to the async
assignment.
async & defer - What's the Difference
This WebKit blog post explains the difference between defer
and async
best:
Both
async
anddefer
scripts begin to download immediately without pausing the parser and both support an optional onload handler to address the common need to perform initialization which depends on the script. The difference betweenasync
anddefer
centers around when the script is executed. Eachasync
script executes at the first opportunity after it is finished downloading and before the window's load event. This means it's possible (and likely) thatasync
scripts are not executed in the order in which they occur in the page. Thedefer
scripts, on the other hand, are guaranteed to be executed in the order they occur in the page. That execution starts after parsing is completely finished, but before the document'sDOMContentLoaded
event.
Who Supports async and defer?
Also from the Safari blog:
In addition to upcoming versions of WebKit-based browsers, Firefox has long supported the defer and onload attributes and support for async was added in version 3.6. Internet Explorer has also long supported the defer attribute. While async is not yet supported, support for the onload attribute was added in version 9.
async FTW!
Seeing that WebKit had implemented async
put a huge smile on my face. Blocking is a huge bottleneck for every website and the ability to easily direct a script to load asynchronously should speed up the web!
Okay… so what is the benefit of the async tag vs defer. It seems that in all use cases defer is just as efficient and more useful as it will prevent nasty dependency problems?
Please explain why async is ftw better than defer…
defer loads the script when everything else is finished. async can load whilst other elements are loading. This is mainly going to be more useful in complex cases (multiple scripts all with the potential to block)
Nice! Way better than putting the scripts at the bottom of the <body>
@benjamin : you could use async for scripts that does not depend on other scripts to run. I’m thinking about scripts such as Google Analytics, for instance.
@David Walsh: is it possible to mix async and defer? I’m explaining my thoughts: If I’ve two scripts A and B that depends both on a library (like mootools), but haven’t any dependencies together, could I do:
1. defer mootools
2. async A
3. async B
so mootools will be loaded first, and then A and B in any order?
So, I’m clarifying my question: what’s the priority between defer and async:
1. defer over async, like above
2. async over defer / none, means A and B could be loaded before mootools
Thanks for your blog David, it’s delightful
@Alexander Mercier you said that it’s possible to mix ‘async’ and ‘defer’. So you’re saying that I can use ‘defer’ for a library (like jQuery) and ‘async’ for any other like Google Analytics. What about top header modernizr.js? Can I use ‘async’ for it?
Walshe… I have been checking your stuff out, and it looks good! The JS looks big and bulky and I am wondering if its going to hurt the first time I implement it. Any advice?
Thank you for the great article Walsh!
@Alexandre: I was also wondering something similar and I read a bit of interesting text in this article:
“The defer attribute may be specified even if the async attribute is specified, to cause legacy Web browsers that only support defer (and not async) to fall back to the defer behavior instead of the synchronous blocking behavior that is the default.”
To better explain my situation: I’m not only interested in making sure my scripts load in the correct order (as you are) but I’m also very interested in each being non-blocking across as many browsers possible (including legacy browsers).
While this may not directly answer your question I believe it may be helpful to your case (and mine). It sounds like async will override defer if it (async) is supported, so it would be safest to give your first script (mootools) a defer attribute, and then give your other scripts (A and B) both async and defer attributes. I could be totally misunderstanding the use of these here, so someone please correct me if I’m wrong.
@Walsh: Do you have any insight you can add this particular topic?
how long does it take for updates to webkit like this to make it out into the wild of production chrome/safari?
it seems like this should have been a standard across all modern browsers long ago (i know, i know, if you had a nickel…), if only for the single use case of allowing publishers to load ads after content. think of all the billions of seconds wasted…
@Alexandre Mercier :
async scripts execute at the first opportunity after download and before window
onload
event. So there is a possibility of script A or script B getting getting executed even before executing MooTools. Because as MooTools is given Defer attribute , it will get the first opportunity of executing only just before theDomContentLoaded
event.So there may be some dependency errors.correct?@ David Walsh,
Post comment button is not working ;-(
i used this to post my comment
Hey, David; My recent tests show that the only browsers to support script async are FireFox 3.6+ and Chrome. I’m running tests for defer, but Safari definitely doesn’t support it; so perhaps it doesn’t have the latest version of Webkit support.
I wrote a simple test which I ran through BrowserCam. The link is here:
http://test.marketruler.com/js/async.php
The embedded async_js.php script does a 2 second delay, then returns its results which set a global value to true.
That test is insanely useful! (and will remain so over time as unsupported browsers release new versions)
Thanks!!!
Awesome Kent! Thanks for doing some legwork!
Well, it’s my business, but no problem. I’ll report back after the defer tests. I wrote an article on our wiki here:
http://wiki.marketruler.com/How_does_JavaScript_run_on_a_web_page%3F
which kind of covers the issue as I understand it.
Final point: Script “defer” attribute is supported by Chrome, FireFox 3.6+, and Internet Explorer 5+ on Windows. Worthwhile if you want to speed up your pages.
Actually, the webkit’s blog isn’t relevant anymore about the
async
attribute. If a script hasasync
attribute it can be executed after theDOMContentLoaded
event was fired:http://dev.w3.org/html5/spec/the-end.html
But since the post was written in 2010 the spec was probably different then.
As you said, the only difference between async and defer is when the script is executed. For me, the browser can run the script very fast, so it doesn’t matter to consider the different speed although the async is a bit faster but not significant..
After all, I still prefer the defer attribute because it guarantees everything will work fine without worries :P
Is it possible for ASYNC scripts to be executed before DEFER scripts? If so, how does one make sure a script like jquery.js is ready for other scripts that will depend on it? Must jQuery be a blocking script (i.e., not using ASYNC or DEFER)?
I think 1 big problem using async and defer is maintaining script dependency (or execution order). For example if we need 2 scripts: jQuery and our custom file which requires jQuery to run, then we should add async or defer to our custom code file.