Defer & Async Attributes in Javascript

The default way of treating a <scipt/> tag by a browser is to pause creating DOM (Document Object Model) and start loading and executing the resource of script but this behaviour leads to two important issues:

  1. The script does not have access to the complete DOM since its creation was paused midway which results in not being able to modify (add handlers) to the DOM properly

  2. Since <script> blocks the browser from creating DOM which results in turning UI unusable/non-interactive

Representation of first issue:

Code:

<html>
  <body>
    <p>Content loaded before execution of script</p>
    <script src="index.js"></script>
    <p id="dynamic_header">Content loaded after execution of script</p>
  </body>
</html>
document.getElementById("dynamic_header").innerHTML ="The content has been modified";

Even after having a script that is supposed to change the content of <p id="dynamic_header">...</p> there is no change which by now we understand is due to the reason that the script was executed even before this part of the DOM was even created.

Representation of second issue:

Code:

<html>
  <head>
    <title>Blog 1</title>
    <meta charset="UTF-8" />
    <script> alert("hello world")</script>
  </head>
  <body>
    <h1>Hello World</h1>
  </body>
</html>

Here we witness how the script blocks the DOM formation when the script is executing.

Note: this behaviour is witnessed by both inline & external scripts

To tackle these issue there are two <script> attributes that solve the problem for us: defer and async.

defer

The defer attribute which is associated with <script> tag tells the browser to not block the creation of DOM when browser comes across script tag but to load the resources from<script> tag parallelly in background and once the DOM is completely created then execute the script at the end. This method fixes our issue regarding blocking the creation of DOM and prevents leading to a condition where script wants to associate a handler to an DOM which is not created yet.

Let us modify our previous code for changing content of <p id="dynamic_header">...</p> but this time we use defer attribute Code:

<html>
  <body>
    <p>Content loaded before execution of script</p>
    <script defer src="index.js"></script>
    <p id="dynamic_header">Content loaded after execution of script</p>
  </body>

This time the content did change and this was possible because we used defer attribute.

async

The async attribute is somewhat similar to defer in a way that both of them make script non-blocking and resources are loaded parallelly while DOM is being created but there is also a significant difference between both of them. Unlike defer, async does not execute once all the DOM is created but it executes immediately after all the resources from the <script> tag have been loaded.

Note: defer & async attribute only works for external scripts

Discussion Point

Looking at defer attribute, it basically executes script tags once DOM in created. So, why don't we just use script tag at then end of our <body/> which will also execute after entire DOM is created? Well, this might sound right but it does come with it's own problems. With defer attribute script is loaded in the background while the DOM in being created but in this way around, the script will start loading after DOM has been created which is result in delay.