Async VS Defer - Understand The JavaScript Execution
Let's understand the loading and execution of a script in the browser with an example.
Do you really understand how the following line gets executed in your browser?
<script src="script.js"></script>
Do you really understand how the browser manages this line? People always say that to put the <script>
tag at the end of the <body>
tag, but do you really know why do they say that? Is there any other place where we can put our <script>
tag? What if we want to put the <script>
tag inside the part of our document as like below...?
<!-- inside the head tag -->
<head>
...
<title> .... </title>
<script src="script.js"></script>
</head>
Aahhh, enough of these questions. Now it's time to understand them.
First and foremost, Yes we can put our <script>
tag wherever we want, but remember one thing that it can affect your page performance in big projects and as well as in small ones too.
So now let's understand exactly how <script>
tag loading works under the hood and most importantly how we can use async
and defer
attributes to speed up our Javascript loading and improve our page performance.
How Browser parse HTML document...
Hold on here! Before understanding how <script>
is loading, Let's understand how HTML document gets parsed in the browser. The browser parses HTML from the top of the document to the bottom, and when it hits a resource, like an <img>
tag it will send a request for that resource and continue parsing. The main point here to note is that the browser does not stop parsing the document to get the resource. This is the reason when you load some web pages then you will see that the images are popping up a little bit late than the content on that page (Mostly happened in Government pages).
Okay then, let's understand how the <script>
tag gets parsed in the document. Whenever the parser hits a normal <script>
tag then the browser gets forced to download that script and execute that first and then again start parsing the HTML document. So this is the reason peoples say us to put our script at the end of the document so they don't delay our page rendering and also they don't get executed before the DOM (Document object model) or you can say just document get rendered.
Now you will be thinking like it's ideal to put the <script>
tag at the bottom of the HTML body, but just take this scenario, what if our HTML document is too large and it takes some time to get downloaded and rendered in the browser then the JavaScript will not start even downloading until all of the document gets rendered which could delay your <script>
download and affect your page performance. This is why the they introduced two attributes async
and defer
to use in the <script>
tag so that we can improve our page performance.
Async and Defer
Both async
and defer
attributes help the browser to load the <script>
without blocking the downloading and rendering of the HTML document and make the <script>
tag work like a <img>
tag or any others external tag in the HTML. So what does it basically mean ?
If we are gonna use any of the attributes then the script will get downloaded along with the HTML document.
Okay, I get it now. But one more doubt here, what's the difference between them...? Don't worry, I got you.
Async vs Defer
Both async
and defer
look like they do the same thing at the first glance, but that's not the case, there is a subtle difference between the two.
Defer waits for the DOM but Async doesn't -
The first and most important difference Is async
doesn't care whether DOM is fully loaded or not, on the other side defer
waits for the DOM to get loaded first and after that, it starts execution of the scripts.
For example, let's say you have 25000 buttons in your HTML document and now select every button of the DOM using both of the scripts and get the length of them.
<head>
<script src="defer.js" defer></script>
<script src="async.js" async></script>
</head>
<body>
<div class="container">
<!-- 25000 buttons -->
</div>
</body>
Here are our script codes...
//! Async script code here
let asyncButton = document.querySelectorAll('button');
console.log(`Async script button count: ${asyncButton.length}`);
// Defer script code here
let deferButton = document.querySelectorAll('button');
console.log(`Defer script button count: ${deferButton.length}`);
And here is the console output...
As you can see now, async
is not waiting for the DOM to get loaded fully and selecting all the buttons loaded at the time of execution of the script and on the other hand, defer
is waiting for the DOM elements to get loaded first and that's why it's selecting every button presented at the DOM.
If your script is dependent on the DOM, then never ever use the
async
attribute, there's the possibility that the element you need get undefined and this is a potential source of bugs.
Defer maintain the order of JS files Async doesn't -
What does it mean though, take another example to understand it? Let's say you will have four scripts. Each script logs the number of that script. Now if we gonna use the async
attribute in the scripts, the order of executing scripts become unpredictable.
<script src="one.js" async></script>
<script src="two.js" async></script>
<script src="three.js" async></script>
<script src="four.js" async></script>
The console output will be something like this...
But what if we use the defer
attribute in every script?
<script src="one.js" defer></script>
<script src="two.js" defer></script>
<script src="three.js" defer></script>
<script src="four.js" defer></script>
And here is the output...
So now you can see clearly that
defer
always maintain the order of the script so if you have scripts that depend on each other then always consider usingdefer
rather thanasync
.
Conclusion
- Adding the
defer
attribute will make sure DOM gets loaded first and then the scripts get executes in the given order. - Adding the
async
attribute will execute the script as soon as it gets loaded and this will not follow any order. So avoid using it if your script is dependent on each other or DOM. - So practically,
defer
is more useful thanasync
, and most of the time you would wantdefer
instead ofasync
. async
is great when you want to load the script in the middle.
That's all about async
and defer
and script loading in JavaScript. If you enjoyed this article, please tell a friend about it or share it on your social media handles and make sure you comment below and share your thoughts about it. Thank you.๐