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.