DEV Community

Cover image for Boost Page Speed with async and defer
Balwant Singh
Balwant Singh

Posted on

Boost Page Speed with async and defer

JavaScript is an essential component in web programming, enabling interactivity and dynamic behaviour on web pages. While HTML and CSS handle the structure and aesthetics, JavaScript brings the page to life.

There are different ways to add JavaScript code to an HTML file. The most common method is to store the JavaScript code in a separate file with a .js extension. Then, you can load that file into the HTML using the script tag. This allows the browser to download and execute the JavaScript code.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Your Page Title</title>
    <script src="your-script.js"></script>
</head>
<body>
    <!-- Content of your webpage goes here -->
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

The issue with loading a JavaScript file in the <head>

When a browser encounters a <script src='...'>...</script> tag in HTML, it pauses building the webpage and immediately executes the script. The browser must wait for the script to download, execute it, and only then can it continue processing the rest of the page.

Rendering without any attributes

This leads to 2 significant problems:

  1. Scripts cannot interact with or modify elements that appear after them in the HTML code. This means they can't add event handlers or make changes to elements lower down the page.
  2. If there is a large script at the top of the page, it causes a delay in displaying the page content. Users have to wait for the script to download and run before they can see the actual content of the page.

The Dirty Workaround:

So how do we fix this problem? One obvious but not-so-good fix is to move the script tag to the end of the <body> tag

<body>
  ...all content is above the script...

  <script src="your-script.js"></script>
</body>
Enter fullscreen mode Exit fullscreen mode

However, this solution is not without its drawbacks. One of the issues is that the browser detects and begins downloading the script only after it has finished downloading the entire HTML document. This can result in noticeable delays, particularly for long HTML documents.

While this delay may go unnoticed by users with fast internet connections, it poses a problem for individuals with slower internet speeds or unreliable mobile connections.

Thankfully, there are two attributes available for the <script> tag that provide solutions to this problem: defer and async.

Async Attribute

The async attribute is ignored if the <script> tag has no src.

<script async src="your-script.js"></script>
Enter fullscreen mode Exit fullscreen mode

The async attribute tells the browser not to wait for the script. Instead, the browser will continue to process the HTML, build DOM. The script downloads “in the background”, and execute once done.

Rendering with Async attribute

Important Considerations When Using the async Attribute

1) The async scripts execute in the load-first order:

It does not guarantee the order of execution of the script. For instance, a smaller script small.js goes second but probably downloads before long.js, so small.js executes first.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Your Page Title</title>
    <script async src="long.js"></script>
    <script async src="small.js"></script>
</head>
<body>
<!-- Content of your webpage goes here -->
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

2) DOMContentLoaded event and async scripts don’t wait for each other:

When it comes to the order of execution, the DOMContentLoaded event and async scripts are independent of each other. The DOMContentLoaded event may occur before or after an async script, depending on factors such as the script's loading time and whether it is already present in the HTTP cache.

<script>
  document.addEventListener('DOMContentLoaded', () => alert("DOM ready!"));
</script>

<script async src="your-script.js"></script>
Enter fullscreen mode Exit fullscreen mode

Defer Attribute

The defer attribute is ignored if the <script> tag has no src.

<script defer src="your-script.js"></script>
Enter fullscreen mode Exit fullscreen mode

The defer attribute tells the browser not to wait for the script. Instead, the browser will continue to process the HTML, and build DOM. The script loads in the background, and then runs when the DOM is fully built.

Rendering with Defer attribute

Important Considerations When Using the defer Attribute

1) defer guarantees the order of execution of scripts just like regular scripts.

It guarantees the order of execution of the script. For instance, To enhance performance, browsers download scripts in parallel therefore smaller script small.js goes second but probably downloads before long.js, but it still waits and runs after long.js executes..

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Your Page Title</title>
    <script defer src="long.js"></script>
    <script defer src="small.js"></script>
</head>
<body>
<!-- Content of your webpage goes here -->
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

2) DOMContentLoaded event handler waits for the deferred script. It only triggers when the script is downloaded and executed.

<script>
  document.addEventListener('DOMContentLoaded', () => alert("DOM ready!"));
</script>

<script defer src="your-script.js"></script>
Enter fullscreen mode Exit fullscreen mode

When should I use what?

1) If the script is modular and does not depend on any other scripts such as independent third-party scripts like counters, and ads then use async.

<!-- Google Analytics is usually added like this -->
<script async src="https://google-analytics.com/analytics.js"></script>
Enter fullscreen mode Exit fullscreen mode

2) If the script relies upon or is relied upon by another script then use defer.

3) If the script is small and is relied upon by an async script then use an inline script with no attributes placed above the async scripts.

Dynamic Scripts

There is another important method of adding a script to a webpage. We can create a script element using JavaScript and add it to the document dynamically. Here's an example:

let script = document.createElement('script');
script.src = "your-script.js";
document.body.append(script);
Enter fullscreen mode Exit fullscreen mode

Once the script is appended to the document, it starts loading immediately.

It's important to note that dynamic scripts behave as async by default. This means that they will load asynchronously, potentially impacting the order of execution and interaction with other elements on the page.

To make it non-async, we can set

script.async = false
Enter fullscreen mode Exit fullscreen mode

What if we put both async and defer attributes in the same script tag?

If you specify both, async takes precedence on modern browsers, while older browsers that support defer but not async will fallback to defer.

Top comments (0)