Async vs Defer - Which Script Tag is More Efficient When Loading JavaScript?

Async vs Defer - Which Script Attribute is More Efficient When Loading JavaScript?

JavaScript is the most popular language in the world. Why? Because its the only well adopted language supported by a Web Browsers that brings dynamics to frontend experience.

Because of that, almost any web application requires from developers to write at least a bit of JavaScript code. While it's not a problem (unless you hate this language 😉), some of us tend to create very complex, frontend heavy applications that load.. well, definitely not fast.

In this article, you'll get familiar with async and defer - two attributes that will speed up your website speed rendering.

Table of contents

    How website rendering works?

    Have you ever wondered how web browsers render websites?

    There are a couple of steps which have to be taken by browser engine to display web page:

    1. Receiving raw bytes of data from the server and transforming them into characters with proper encoding.
    2. Parsing characters to extract HTML structures. Without this process data returned from a server would be just a bunch of meanless characters. This step is called tokenization, and it produces tokens.
    3. Converting tokens into nodes - distinct objects with properties.
    4. Linking nodes to create data structures, known as DOM (Document Object Model) and CSSOM (CSS Object Model).

    There is one important website optimization rule that applies to this process - ensuring that both the HTML and CSS are delivered to the browser as quickly as possible. In other words, you don't want to interrupt the process of constructing Object Model in any way (learn more about this process).

    What's the actual speed problem when loading JavaScript?

    To understand why these four steps are important in terms of JavaScript load time let's take a look at a typical scaffold of HTML code:

       <!-- Meta tags, Links, etc -->
       <script type="text/javascript" src=[link-to-script]></script>
       <!-- Your website content -->

    During the process of building the DOM structure, the browser will send a request to fetch any related resources that your website links to.

    In this case, we are linking to the external JavaScript code. Let's remap rendering timeline for this example:

    Script rendering in head with no attribute

    As you can see, the DOM object (which is a final result of the fourth step described before) is not ready until the JavaScript code is fetched and executed. Why is this a very bad case scenario? Because user is not going to see a website until the browser engine finishes building DOM.

    And it's not only JavaScript dependencies that delay DOM ready state. It's also CSS, images, videos, etc. Browser engine has to load all resources first, to finish rendering.

    Developers often move JavaScript eternal scripts to the bottom of the page in the following way:

       <!-- Meta tags, Links, etc -->
       <!-- Your website content -->
       <script type="text/javascript" src=[link-to-script]></script>

    Since most of the time your JavaScript code will manipulate the body contents, it makes sense to place scripts at the end of the body tag.

    Before the web engine reaches this point, it's already able to render most of the page content, which is a good thing since the user will be able to see the website before JavaScript execution.

    Script rendering in body with no attribute

    Is there any downside to this solution? If the script uses document.write to insert part of the page's content, it can't be moved lower in the page, therefore, you can't place it at the end of the body tag.

    Also, keep in mind that it doesn't affect document.ready state because the browser has not yet finished building DOM.

    To sum up, we are able to render page faster, but we still have to wait for scripts to be loaded synchronously.

    Meet async attribute for external scripts

    In the typical case scenario, when the browser engine meets the following script:

    <script type="text/javascript" src=[link-to-script]>

    it stops further processing to download and execute JavaScript code.

    You can speed it up with async attribute:

    <script type="text/javascript" src=[link-to-script] async></script>

    Once again, let's illustrate in timeline how your website is going to rendered by browser engine, but in this case, with async attribute:

    Script rendering in body with async attribute

    As you can see, we can save time previously spent on the script download process. With async, browser engine is fetching the script asynchronously in parallel, and once the download is completed it immediately stops further operations to execute JavaScript code.

    With a lot of script tags included in your HTML, async attribute saves a lot of time. Just imagine being able to download 10 scripts in parallel while the browser engine is busy building the rest of DOM.

    Is this a perfect solution? Not really. While we can save time on the download process, we are not exactly sure when each of the scripts will be executed.

    Also, if your JavaScript code depends somehow on the DOM object it might try to modify its structure before it's complete. Of course, you can fix this step with events, but it would be nice to somehow make it work more in a more efficient way.

    Meet defer attribute for external scripts

    It's as easy as in case of async to add defer attribute to your JavaScript tag:

    <script type="text/javascript" src=[link-to-script] defer></script>

    Let's visualize how the process of rendering DOM will look like with defer attribute:

    Script rendering in body with defer attribute

    The problem we had with the async attribute is gone with defer. JavaScript code is being fetched in parallel and executed exactly after the browser engine is finished parsing HTML.

    It's what we needed since the website, in this case, is displayed to the user without two big latency sources:

    • downloading external JavaScript code,

    • executing fetched code during DOM render.

    Is defer and async a holy grail for JavaScript load speed?

    As with everything in web programming, there are no holy grails. Why? Because of browser versions support.

    You can check the current support here:

    Should you care? Well, there might be some bugs in older browsers, like the one with defer in IE9, but unless you need to support these cases, you should go with defer for most of the time, since it brings the fastest way to load DOM in the browser.


    Async and defer are great script tag attributes that allow you to speed up building the DOM. Since in SEO speed matters, you should be using them to rank higher in SERP.

    If you're not technical, and you own website based on Wordpress, worry not - there are a lot of plugins out there for async script loading.

    How do you load JavaScript code on your website? Let us know in the comments if adding defer or async improved your page load speed.

    Download our ebook
    Sign to our Newsletter
    Szymon Soppa Web Developer
    Szymon Soppa Curiosum Founder & CEO

    Read more
    on #curiosum blog

    Why Disqus slows down your page and how to fix it?

    There are a lot of pages using Disqus as a way to communicate with readers. It's a great comments widget that comes with a free plan included which is probably one of the main reasons for its success.

    It has, however, a drawback - using it causes an increase in page load time. In this article, you'll learn how to fix that with a simple hack.

    What's the difference between alias, import, require and use in Elixir? A complete guide with use cases

    In most programming languages we often deal with instructions responsible for handling dependencies. Elixir is no different.

    In Elixir, dependency is nothing more than compiled module which for some reason you want to use in another module. There are a couple of instructions that we use in Elixir to either make it easier or possible to interact with modules.

    In this blog post I'll explain and present use case examples of four of them:

    • alias,
    • require,
    • import,
    • use.