Understanding async and defer attribute

Understanding async and defer attribute

Script loading techniques and their impact on performance

When you want to run the same JavaScript on several pages of your website, you create a separate external JavaScript file with the .js extension and add it to your HTML file using the <script> tag and refer to it using the src attribute like so:

<script src="path-to-js-file.js"></script>

Now, if the executable data is larger than the HTML file, it leads to what is called render-blocking. Why? The browser has to first download and process the content of the external script file before it renders the entire web page.

Well, async and defer to the rescue!! But before we go there, we need to first understand a couple of other topics. Let's get into it, shall we?

Topics that will be covered:

  1. HTML Parsing.
  2. Difference between adding the script file in the head and body.
  3. Async and defer attributes and when to use them.

Prerequisites:

This post assumes you have the basic knowledge of the following:

  • HTML
  • CSS
  • JavaScript syntax.

Introduction

HTML Parsing

An external script file can be added to your HTML in two places:

  1. Either in the <head> section
  2. Or in the <body> section

But what difference does it make as to where we add them? Let’s learn how the browser loads a web page to understand.

  • The browser fetches the HTML file and parses it into a DOM tree.
  • HTML parsing involves tokenization and tree construction. HTML tokens include start and end tags, as well as attribute names and values. The parser parses tokenized input into the document, building up the document tree.
  • The HTML parser continues to parse the external resources/references that it encounters.
  • When the CSS file is encountered, it parses the text into CSS Object Model (CSSOM) which is then used for styling and painting the content on the screen.
  • But, when the browser comes across a <script> tag, it pauses the execution process. It then downloads the content of the script and continues parsing the HTML code, as shown below:

image.png

We can see how this can cause problems. If you have an HTML file with many <script> tags, those tags may cause a significant delay in parsing the HTML file.

Adding script in the head:

Adding script tags in the head means that the script file is fetched before the HTML is parsed and loaded.

<html>
   <head>
     <title>Add script in the head</title>
     <script src="./src/index.js"></script>
   </head>
   <body>
     <!-- DOCUMENT CONTENT -->
   </body>
 </html>

image.png

Obviously, that's a no-no as it causes delayed parsing.

Adding script in the body:

Now that we know how the browser parses HTML, it makes sense to add the script tag in the body to avoid delays in the document rendering, right? That way the entire DOM content is rendered before the script tag is encountered.

<html>
   <head>
     <title>Add script in the body</title>
   </head>
   <body>
     <!-- DOCUMENT CONTENT -->
     <script src="./src/index.js"></script>
   </body>
 </html>

image.png

Although this is the most preferred technique, this can be problematic if we have multiple script files or if they are huge! The parser will only start downloading the script content when it encounters the script tag at the end of the document, which can be time-consuming, thereby causing further delays and degrading the performance of our website.

To overcome this, HTML5 provided two features - async and defer - that eliminate render-blocking. These are added as attributes to the script tag.

gif

Using the async attribute:

When using the async attribute in our script tag, the script is independent of the HTML parsing. This means the parser will download the JavaScript in the background and continue parsing as normal without waiting. When the JavaScript is done being downloaded, then the parser will immediately stop parsing and execute the JavaScript.

<script async src="script.js"></script>

image.png

When to use Async?

  • If the JS code is too big, the use of async may still cause a delay in parsing by taking too long to execute.
  • The JavaScript files are not executed in the order they are defined in the HTML, but in the order that they are downloaded.

Keeping the above points in mind, async can be used for any small JS code which is not dependent on anything else.

Using the defer attribute:

When we use the defer attribute in our script tag, the JavaScript loads in the background and only runs when the entire HTML document is parsed. does not wait to fetch the

<script defer src="script.js"></script>

image.png

When to use Defer?

  • The JavaScript files are downloaded before any of them can be executed when defer is used.
  • It also preserves the order of JavaScript as if it was loaded without the defer attribute.

Loading JavaScript with the defer attribute is essentially the same as loading JavaScript at the end of the body, but it will start the download sooner.

Conclusion

When your JavaScript execution is not needed for rendering critical content of the page, using either defer or async attribute can greatly enhance the user experience.

Defer has the advantage of never blocking the HTML parsing, while async has the advantage of loading the script independently of others.

Thank you for sticking to the end. If you found this blog helpful, let me know in the comments below and share it with your fellow devs!