Async VS Defer - Understand The JavaScript Execution
Tags: javascript, webdev, programming, codenewbie
Published: 2021-08-14 09:32:03

As a web developer, how many times you have written this line in your code?
```
<script src="script.js"></script>
```
Probably too many times to count, but do you really understand how the browser handles this simple line of code? We have always been advised to put our `<script>` tag at the end of the `<body>` tag, but again why is that so...? Is there any other place where we can put our `<script>` tag? What if we put the `<script>` tag inside the `<head></head>` tag of our HTML document like - 
```
<!-- inside the head tag -->
<head>
    ...
    <title> .... </title>
    <script src="script.js"></script>
</head>
```
![Gif here](https://media.giphy.com/media/bN4Gf6GEs9OtW/giphy.gif)
Aahhh, enough of these questions. Now it's time to understand all of 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. 

So now let's understand exactly how `<script>` tag loading works and most importantly how we can use `async` and `defer` to speed up our Javascript loading and improve our page performance. 

## How Browser Parse HTML

Before understanding how `<script>` is loading, we first need to understand how the browser parses HTML. Luckily, it's pretty straightforward. The browser will parse HTML from the top of the document to the bottom, and when it hits a resource, like an `<img>` tag it will send out a request for that resource and continue parsing. The important thing to note is that the browser does not stop parsing the HTML to get the `img src`. This is why when you load a web page you may notice the page jumps around as the images pop in since they are loaded in the background and may finish downloading after the HTML is parsed.
 
But that's not the case with the `<script>` tag. When the browser comes across a `<script>` tag when loading HTML, the browser is forced to download and parse the entire `<script>` and evaluate it first, before it can continue with reading the rest of the HTML to build the DOM. This is why we are advised to put our `<script>` tag at the bottom of our HTML body so they don't delay the parsing of the HTML.

Now you can just think that putting the `<script>` tag at the bottom of the HTML body is ideal, but what if the HTML is too large and it takes some time to get downloaded and parsed then the JavaScript will not start downloading until all of the HTML is parsed which could delay your `<script>` download and affect your page performance. This is why the `async` and `defer` attributes were created.

## Async and Defer

Both `async` and `defer` attributes load the `<script>` without blocking the DOM and make the `<script>` tag work like as a `<img>` tag to the parser as described above. This means that the script will be fetched in the background and continue parsing as normal without waiting. Okay, that seems fair but what's the difference between them...? Here we go then.

## 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...


![temp1.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1628732144264/ogBB9E8iI.png)

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...


![temp2.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1628733846390/0AUL0x1t4.png)

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...

![temp3.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1628736741526/pdhVcVeJS.png)

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 using `defer` rather than `async`.

## 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 than `async`, and most of the time you would want `defer` instead of `async`.
- `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.🙏

 [Follow me on Twitter](https://twitter.com/jeetsdev)