Load Non-blocking JavaScript with HTML5 Async and Defer

By Craig Buckler

Loading JavaScript is one of the biggest performance bottlenecks. Under normal circumstances, a script tag causes the browser to halt rendering, load a file, and run the code. The browser is blocked from doing other useful work because your JavaScript could write to the page, modify existing elements, or redirect to another URL.For this reason, it’s good practice to place script tags at the bottom of the HTML, just before </body>. The browser may be unresponsive for a second or two, but it’s not noticeable because the main content has loaded.However, even that solution is inadequate for today’s multi-megabyte client-side applications. In extreme cases, it’s necessary to load large code libraries using script tag injections or Ajax techniques. This prevents blocking, but requires additional code and rigorous testing to ensure that scripts run in the correct order in all browsers.

The defer Attribute

The defer attribute makes a solemn promise to the browser. It states that your JavaScript does not contain any document.write or DOM modification nastiness:

<script src="file.js" defer></script>

The browser will begin to download file.js and other deferred scripts in parallel without stopping page processing.defer was implemented in Internet Explorer version 4.0 — over 12 years ago! It’s also been available in Firefox since version 3.5.While all deferred scripts are guaranteed to run in sequence, it’s difficult to determine when that will occur. In theory, it should happen after the DOM has completely loaded, shortly before the DOMContentLoaded event. In practice, it depends on the OS and browser, whether the script is cached, and what other scripts are doing at the time.

The async Attribute

async has been introduced in HTML5:

<script src="file.js" async></script>

async is identical to defer, except that the script executes at the first opportunity after download (an optional onload attribute can be added to run a specific function). You can’t guarantee that scripts will execute in sequence, but they will have loaded by the time the window onload event fires.There’s support for async in Firefox 3.6, Opera 10.5, and the latest WebKit build, so it should appear in the next versions of Chrome and Safari. IE9 is yet to support async, but the IE team could easily add it as an alias for defer. You can use both async and defer to support all browsers — even IE4.Perhaps within a few months, we’ll finally have a native, non-blocking JavaScript loading method that works in all browsers.

Note: Opera’s Delayed Script Execution

Opera provides an experimental Delayed Script Execution facility, which can be enabled in about:config. It remembers where an async script was loaded on the page, so it’s possible to use document.write or modify the DOM.The feature would immediately benefit widgets and adverts that block page loading. Let’s hope Microsoft, Mozilla, and WebKit follow Opera’s lead.

  • edvakf

    Opera does not support async nor defer unless you opt in Delayed Script Execution as you noted. DSE is turned on by default on mobile Operas and when Opera Turbo is turned on.

  • I wouldn’t recommend working with scripts that execute in an unknown order — the predictability of objects you loaded in one script being available in another is usually quite important.

  • Why didn’t they just use defer…why make a whole new attribute when it would just been easier to use defer…

    • It does seem odd. I suspect it’s been done because they act slightly differently — although defer would appear to be the most useful because scripts should run in order.

  • Jack Matier

    It sounds like they do two different things. One (defer) executes the scripts in the order they were called (so it can handle dependencies I assume) while the other executes them as soon as they are loaded (async).

    If I understand this correctly, you can always not use async for things your scripts depend on so they will be the first things to load. It’s not a perfect world and personally I prefer the defer method of doing things.

  • When using defer and/or async do I still need to put the script tags at the bottom?

    • In general, I’d suggest you should. Although defer/async won’t stop the page from rendering, browsers usually only download 4 files at a time. Therefore, 4 large defer/async scripts could prevent images loading.

      However, it’ll really depend on your page and what you want to achieve. You could benefit from loading a large defer/async script at the top of the page so it’s available sooner.

  • Serg

    Thank you for helpful post. I’ve never heard about defer/async flags before.
    To make it clear, does it mean that, for example, javascript libraries (like jquery, prototype etc.), that are actually, as far as I know, don’t do any document.write while running, could be loaded with these flags?

    • Yes you could load a library such as jQuery using defer/async. But it wouldn’t make a significant difference if you’re loading them at the end of your HTML page.

  • Brian

    Opera needs to enable async support by default. Firefox supports the async attribute, and all other browsers (except Opera) will load scripts asynchronously if they are injected as a script DOM element. Opera is the only browser that doesn’t support async scripts out of the box.

  • Ritu Dhall

    I tried using ‘defer’ on my page eg

    but the same warning message is coming in IE8.

    Can anybody help??

    • I suspect you’re either trying to defer a script which modifies the DOM or the deferred script is loaded after a script which depends on it.

      What warning message do you see?

  • Sascha

    Both, async and defer doesn’t realy support exec. order! It depends from Browser to Browser. Best thing to do is use a simple scriptloader or a combination with a module system that uses the amd specs.

Get the latest in JavaScript, once a week, for free.