Load Non-blocking JavaScript with HTML5 Async and Defer

Share this article

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.

Frequently Asked Questions (FAQs) about Non-Blocking, Async, and Defer in JavaScript

What is the difference between async and defer in JavaScript?

Both async and defer are attributes that can be added to a script tag in HTML to control how JavaScript files are loaded and executed. The async attribute loads and executes the script asynchronously with the rest of the webpage. This means that the script is executed as soon as it is loaded, without waiting for the rest of the webpage to load. On the other hand, the defer attribute also loads the script asynchronously, but it defers the execution of the script until the rest of the webpage has loaded. This can be useful for scripts that rely on the DOM being fully loaded before they can run.

Where should I place my JavaScript code in an HTML document?

The placement of JavaScript code in an HTML document can significantly impact the loading performance of your webpage. Traditionally, scripts are placed in the head section of the HTML document. However, this can block the rendering of the webpage until the script is loaded and executed. To avoid this, it is often recommended to place scripts just before the closing body tag. This allows the HTML document to load and render before the script is executed. Alternatively, you can use the async or defer attributes to control the loading and execution of scripts without blocking the rendering of the webpage.

Is it better to put JavaScript code in an external file or directly in the HTML file?

There are pros and cons to both approaches. Putting JavaScript code in an external file can make your HTML file cleaner and easier to read. It also allows the browser to cache the script, which can improve loading performance for repeat visits. However, it does require an additional HTTP request to load the script, which can slow down the initial load time. On the other hand, putting JavaScript code directly in the HTML file can eliminate the need for an additional HTTP request, but it can make the HTML file messy and harder to maintain, especially for larger scripts.

What does non-blocking mean in JavaScript?

Non-blocking in JavaScript refers to the ability to load and execute scripts without blocking the rendering of the webpage. This is achieved by loading the script asynchronously, either by placing the script at the bottom of the HTML document, or by using the async or defer attributes in the script tag. Non-blocking scripts can improve the loading performance of your webpage, as the browser can continue to load and render the rest of the webpage while the script is being loaded and executed.

How does the browser handle multiple scripts with async or defer attributes?

When multiple scripts are marked with the async attribute, the browser loads and executes them as soon as they are available, in no particular order. This means that scripts that are smaller or closer to the top of the HTML document may be executed before others. When multiple scripts are marked with the defer attribute, the browser loads them in the order they appear in the HTML document, but defers their execution until the rest of the webpage has loaded. This ensures that scripts are executed in the correct order, even if they are loaded asynchronously.

Can I use async and defer attributes together in the same script tag?

Yes, you can use both async and defer attributes in the same script tag. However, their behavior depends on the browser. In modern browsers that support both attributes, the async attribute takes precedence over the defer attribute. This means that the script will be loaded and executed asynchronously, as soon as it is available. The defer attribute is ignored. In older browsers that do not support the async attribute, the defer attribute is used instead, if it is present.

What happens if a script with the async or defer attribute fails to load?

If a script with the async or defer attribute fails to load, the browser will simply move on to the next task, without blocking the rendering of the webpage. This is one of the advantages of using async or defer, as it allows the webpage to continue loading and rendering, even if a script fails to load. However, it is important to handle script loading errors properly, to ensure that your webpage functions correctly even if a script fails to load.

How can I check if a browser supports the async or defer attribute?

You can check if a browser supports the async or defer attribute by using feature detection in JavaScript. This involves testing if the async or defer property exists on a script element. If the property exists, then the browser supports the attribute. If not, then the browser does not support the attribute.

Can I use the async or defer attribute with inline scripts?

No, the async and defer attributes only work with external scripts. They have no effect on inline scripts. If you want to load and execute an inline script asynchronously, you will need to use other techniques, such as dynamically creating a script element with JavaScript.

What is the difference between async, defer, and non-blocking in terms of performance?

All three techniques – async, defer, and non-blocking – aim to improve the loading performance of your webpage by controlling how scripts are loaded and executed. The async attribute loads and executes scripts as soon as they are available, without waiting for the rest of the webpage to load. The defer attribute also loads scripts asynchronously, but defers their execution until the rest of the webpage has loaded. Non-blocking scripts are loaded and executed without blocking the rendering of the webpage. The best technique to use depends on the specific needs of your webpage and scripts.

Craig BucklerCraig Buckler
View Author

Craig is a freelance UK web consultant who built his first page for IE2.0 in 1995. Since that time he's been advocating standards, accessibility, and best-practice HTML5 techniques. He's created enterprise specifications, websites and online applications for companies and organisations including the UK Parliament, the European Parliament, the Department of Energy & Climate Change, Microsoft, and more. He's written more than 1,000 articles for SitePoint and you can find him @craigbuckler.

javascript
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week