Async vs Defer - Which Script Tag Attribute is More Efficient when Loading JavaScript?
JavaScript is the most popular language in the world. Why? Because it's the only well-adopted language supported by Web Browsers that brings dynamics to the frontend experience.
Because of that, almost any web application requires developers to write at least a bit of JavaScript code. While it's not a problem (unless you hate this language 😉), some of us tend to create very complex, frontend-heavy applications that load.. well, definitely not fast.
In this article, you'll get familiar with async and defer - two script tag attributes that will speed up your website's rendering.
How does the website rendering work?
Have you ever wondered how web browsers render websites?
There are a couple of steps which have to be taken by the browser engine to display a web page:
- Receiving raw bytes of data from the server and transforming them into characters with proper encoding.
- Parsing characters to extract HTML structures. Without this process, data returned from a server would be just a bunch of meanless characters. This step is called tokenization, and it produces tokens.
- Converting tokens into nodes - distinct objects with properties.
- Linking nodes to create data structures, known as DOM (Document Object Model) and CSSOM (CSS Object Model).
One important website optimization rule applies to this process - ensuring that both the HTML and CSS are delivered to the browser as quickly as possible. In other words, you don't want to interrupt the process of constructing the Object Model in any way (learn more about this process).
What's the actual speed problem when loading JavaScript?
Fetching the script in HTML head tag
To understand why these four steps are important in terms of JavaScript load time, let's take a look at a typical scaffold of HTML code:
<html>
<head>
<!-- Meta tags, Links, etc -->
<script src=[link-to-script] type="text/javascript"></script>
</head>
<body>
<!-- Your website content -->
</body>
</html>
During the process of building the DOM structure, the browser will send a request to fetch any related resources that your website links to.
In this case, we are linking to the external JavaScript code. Let's remap the rendering timeline for this example:
As you can see, the DOM object (which is the final result of the fourth step described before) is not ready until the JavaScript code is fetched and executed. Why is this a very bad case scenario? Because user is not going to see a website until the browser engine finishes building DOM.
And it's not only JavaScript dependencies that delay DOM ready state. It's also CSS, images, videos, etc. The browser engine has to load all resources first to finish rendering.
Fetching the script at the end of HTML body tag
Developers often move JavaScript eternal scripts to the bottom of the page in the following way:
<html>
<head>
<!-- Meta tags, Links, etc -->
</head>
<body>
<!-- Your website content -->
<script src=[link-to-script] type="text/javascript"></script>
</body>
</html>
Since most of the time, your JavaScript code will manipulate the body contents, it makes sense to place the script tag at the end of the body tag.
Before the web engine reaches this point, it's already able to render most of the page content, which is a good thing since the user will be able to see the website before JavaScript execution.
Is there any downside to this solution? If the script uses document.write
to insert part of the page's content, it can't be moved lower on the page; therefore, you can't place it at the end of the body tag.
Also, keep in mind that it doesn't affect the document.ready
state because the browser has not yet finished building DOM.
To sum up, we are able to render a page faster, but we still have to wait for scripts to be loaded synchronously.
Meet script async attribute for external scripts
In the typical case scenario, when the browser engine meets the following script tag:
<script src=[link-to-script] type="text/javascript">
it stops further processing to download and execute JavaScript code.
You can speed it up with the script async
attribute:
<script src=[link-to-script] type="text/javascript" async></script>
Once again, let's illustrate in timeline how your website is going to be rendered by the browser engine, but in this case, with the script async
attribute:
As you can see, we can save time previously spent on the script download process. With the script async attribute, the browser engine fetches the script asynchronously in parallel, and once the download is completed, it immediately stops further operations and executes JavaScript code.
With a lot of script tags included in your HTML, the script async
attribute saves a lot of time. Just imagine being able to download 10 scripts in parallel while the browser engine is busy building the rest of the DOM.
Is this a perfect solution? Not really. While we can save time on the download process, we are not exactly sure when each of the scripts will be executed.
Also, if your JavaScript code depends somehow on the DOM object, it might try to modify its structure before it's complete. Of course, you can fix this step with events, but it would be nice to somehow make it work more efficiently.
Meet defer attribute for external scripts
It's as easy as in the case of async to add the script defer
attribute to your JavaScript tag:
<script src=[link-to-script] type="text/javascript" defer></script>
Let's visualize what the process of rendering DOM will look like with the defer
attribute:
The problem we had with the async
attribute is gone with the defer
attribute. JavaScript code is being fetched in parallel and executed exactly after the browser engine is finished parsing HTML.
It's what we needed since the website, in this case, is displayed to the user without two big latency sources:
-
downloading external JavaScript code,
-
executing fetched code during DOM render.
How and when to use Async and defer attributes?
As with everything in web programming, there are no holy grails. Why? Because of browser versions support.
You can check the current support here:
Should you care? Well, there might be some bugs in older browsers, like the one with defer in IE9, but unless you need to support these cases, you should go with the defer
attribute for most of the time, since it brings the fastest way to load DOM in the browser.
Summary
Async and defer are great script tag attributes that allow you to speed up building the DOM. Since in SEO speed matters, you should use them to rank higher in SERP.
If you're not technical, and you own a website based on WordPress, worry not - there are a lot of plugins out there for async script loading.
How do you load JavaScript code on your website? Let us know in the comments if adding defer
or async
improved your page load speed.
FAQ
What are the main differences between async and defer script tag attributes?
The main differences between async
and defer
attributes in script tags involve how they download and execute JavaScript. Async
downloads scripts asynchronously while the HTML parses and executes them as soon as they are downloaded, potentially interrupting the parser. Defer
, however, downloads scripts asynchronously too but defers their execution until after the HTML parsing is completed.
How does the async
attribute affect the loading of JavaScript files?
The async
attribute allows a browser to download JavaScript files asynchronously while continuing to parse the HTML document. Scripts loaded with async
are executed immediately after they are downloaded, which can disrupt the HTML parsing process.
How does the defer
attribute improve JavaScript loading compared to async
?
The defer
attribute also enables asynchronous downloading of JavaScript files but delays their execution until after the HTML document has been fully parsed. This approach ensures that scripts do not interfere with the initial page rendering, leading to a smoother loading experience.
When should you use the async
attribute for script tags?
Use the async
attribute for scripts that do not depend on other scripts and do not modify the DOM immediately. It's suitable for scripts that do not need to wait for the entire page to load, such as tracking scripts or ads.
When is it more appropriate to use the defer
attribute in script tags?
The defer
attribute is best used for scripts that need to wait for the entire HTML to be parsed before execution, especially if they depend on DOM elements or other scripts. It ensures scripts execute in order and only after the HTML document is fully parsed.
What are the implications of placing JavaScript tags in the HTML head without async or defer attributes?
Placing JavaScript tags in the HTML head without async
or defer
attributes causes browsers to pause HTML parsing to download and execute scripts, which can significantly delay page rendering and affect user experience.
Can you use async and defer attributes with inline script tags?
Async
and defer
attributes are not applicable to inline script tags as these attributes only affect external scripts linked via the src
attribute. Inline scripts are executed immediately where they are located in the HTML.
How do browser support and compatibility impact the use of async and defer attributes?
Browser support and compatibility can impact the effective use of async
and defer
attributes. While most modern browsers support both, there may be inconsistencies or bugs in older browsers. Checking current browser support for these attributes is recommended.
How do async and defer attributes contribute to SEO and page speed?
Both async
and defer
attributes can improve page load speed by altering how JavaScript is loaded and executed. Faster page load times contribute positively to SEO as they enhance the user experience and can lead to higher rankings in search engine results pages.