Async vs Defer in JavaScript: Which is Better?🤔

Async vs Defer in JavaScript: Which is Better?🤔

Hi everyone! I hope you’re doing good. This article will explore an interesting Javascript topic. async and defer are attributes used when including external JavaScript files in HTML documents. They affect how the browser loads and executes the script. Let's learn about them in detail.

Default Behaviour

We generally connect our HTML page with external javascript with <script> tag. Traditionally, JavaScript <script> tags were often placed in the <head> section of the HTML document. However, doing so means that the parsing of the HTML is blocked until the JavaScript file is fetched and executed, leading to slower page load times. Nowadays, we mostly prefer to keep the <script> tag after all the contents of the <body> element to the page get loaded first.

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

Here's how HTML parsing and script execution takes place

Async

When we include a script with the async attribute, it tells the browser to download the script asynchronously while parsing the HTML document. The script is downloaded in the background without blocking the HTML parsing process.

Once the script is downloaded, it's executed asynchronously, meaning it can run at any time, even before the HTML document has finished parsing.

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

If multiple scripts are loaded asynchronously, they will execute as soon as they finish downloading, regardless of their order in the document. It is useful when the script doesn't depend on the DOM being fully loaded or other scripts.

Defer

When we include a script with the defer attribute, it also tells the browser to download the script asynchronously while parsing the HTML document.
However, the execution of the script is deferred until after the HTML document has been parsed.

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

Scripts with the defer attribute will execute in the order they appear in the document. It is useful when the script relies on the DOM being fully parsed or when script execution order is important.

Can you defer inline scripts?

The defer attribute doesn't work with inline scripts, only external scripts. When the browser encounters a script tag within the HTML document, the script executes immediately upon discovery. Applying the defer attribute to an inline script has no effect, since the browser executes the script during the parsing process.

Deferring execution with DOMContentLoaded

Although defer doesn’t work for inline scripts, you can achieve the same effect by wrapping your code inside an event listener for the DOMContentLoaded event. Here’s how:

<script>
  document.addEventListener("DOMContentLoaded", () => {
    // Inline script
  });
</script>

This approach ensures that your script runs only after the HTML document has been completely parsed, similar to how external scripts are deferred with the defer attribute.

What if inline scripts depend on a deferred script?

When inline scripts depend on deferred scripts, such as jQuery or other libraries, there may be issues with the page load. This is because the inline script may execute before the deferred script has fully loaded.

If the inline script tries to access global variables or functions that have not yet been defined, the inline script will fail.

On this page we can see an example where an inline script depends on a deferred script. The following error appears in the console: Uncaught ReferenceError: $ is not defined

If we inspect the HTML document we can see the inline script that depends on the deferred script.

This script selects .vimeo-video elements using jQuery ($), initializes a Vimeo player, and hides the .vimeo-preloader when a video starts playing. As the jQuery script is deferred, the inline script runs before jQuery loads, causing the "$ is not defined" error.

<script>
  $(".vimeo-video").each(function () {
    let iframeVideo = $(this);
    let iframePlayer = new Vimeo.Player(iframeVideo[0]);
    iframePlater.on("play", function () {
      setTimeout(function () {
        $(iframeVideo).siblings(".vimeo-preloader").css("display", "none");
      }, 500);
    });
  });
</script>

Wrapping the inline script with the DOMContentLoaded event listener will resolve the problem, as this ensures that the inline script only runs after the entire HTML document is parsed, and the deferred script has loaded.

<script>
  document.addEventListener("DOMContentLoaded", function () {
    $(".vimeo-video").each(function () {
      let iframeVideo = $(this);
      let iframePlayer = new Vimeo.Player(iframeVideo[0]);
      iframePlater.on("play", function () {
        setTimeout(function () {
          $(iframeVideo).siblings(".vimeo-preloader").css("display", "none");
        }, 500);
      });
    });
  });
</script>

Conclusion

Both async and defer allow the HTML parsing process to continue without waiting for the script to be downloaded.

The difference lies in when the script is executed:
With async, the script executes as soon as it's downloaded, potentially before the HTML document is fully parsed. With defer, the script executes only after the HTML document is fully parsed, but before the DOMContentLoaded event.

One of the important things to note is, that we should only use async when we have scripts that can run independently and don't rely on the DOM structure, and we use defer when we need to maintain script execution order or depend on the DOM structure.

I hope you liked this article and if you did don’t forget to give it a like! 😃

SUBSCRIBE FOR NEW ARTICLES

@
comments powered by Disqus