async defer javascript file html parsing src attribute async scripts javascript files defer parsing javascript defer attributes

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

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

Table of contents

    Because of that, almost any web application requires 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 script tag attributes that will speed up your website's rendering.

    How does the website rendering work?

    Have you ever wondered how web browsers render websites?

    There are a couple of steps which have to be taken by the browser engine to display a 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).

    One important website optimization rule 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 the Object Model in any way (learn more about this process).

    What's the actual speed problem when loading JavaScript?

    Fetching the script in HTML head tag

    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:

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

    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 the rendering timeline for this example:

    Script rendering in head with no attribute async defer html parsing eliminate render blocking javascript executed immediately javascript file separately load scripts

    As you can see, the DOM object (which is the 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. The browser engine has to load all resources first to finish rendering.

    Fetching the script at the end of HTML body tag

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

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

    Since most of the time, your JavaScript code will manipulate the body contents, it makes sense to place the script tag 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 js defer js script async async load js defer attribute in js

    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 on the page; therefore, you can't place it at the end of the body tag.

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

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

    Meet script async attribute for external scripts

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

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

    it stops further processing to download and execute JavaScript code.

    You can speed it up with the script async attribute:

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

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

    Script rendering in body with async attribute script loads all the scripts async defer attributes other scripts high priority javascript resources js code

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

    With a lot of script tags included in your HTML, the script 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 the 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 efficiently.

    Meet defer attribute for external scripts

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

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

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

    Script rendering in body with defer attribute deferred scripts html parser other external scripts async defer general javascript resources defer js

    The problem we had with the async attribute is gone with the defer attribute. 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.

    How and when to use Async and defer attributes?

    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 the defer attribute for most of the time, since it brings the fastest way to load DOM in the browser.

    Summary

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

    If you're not technical, and you own a 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.

    FAQ

    What are the main differences between async and defer script tag attributes?

    The main differences between async and defer attributes in script tags involve how they download and execute JavaScript. Async downloads scripts asynchronously while the HTML parses and executes them as soon as they are downloaded, potentially interrupting the parser. Defer, however, downloads scripts asynchronously too but defers their execution until after the HTML parsing is completed.

    How does the async attribute affect the loading of JavaScript files?

    The async attribute allows a browser to download JavaScript files asynchronously while continuing to parse the HTML document. Scripts loaded with async are executed immediately after they are downloaded, which can disrupt the HTML parsing process.

    How does the defer attribute improve JavaScript loading compared to async?

    The defer attribute also enables asynchronous downloading of JavaScript files but delays their execution until after the HTML document has been fully parsed. This approach ensures that scripts do not interfere with the initial page rendering, leading to a smoother loading experience.

    When should you use the async attribute for script tags?

    Use the async attribute for scripts that do not depend on other scripts and do not modify the DOM immediately. It's suitable for scripts that do not need to wait for the entire page to load, such as tracking scripts or ads.

    When is it more appropriate to use the defer attribute in script tags?

    The defer attribute is best used for scripts that need to wait for the entire HTML to be parsed before execution, especially if they depend on DOM elements or other scripts. It ensures scripts execute in order and only after the HTML document is fully parsed.

    What are the implications of placing JavaScript tags in the HTML head without async or defer attributes?

    Placing JavaScript tags in the HTML head without async or defer attributes causes browsers to pause HTML parsing to download and execute scripts, which can significantly delay page rendering and affect user experience.

    Can you use async and defer attributes with inline script tags?

    Async and defer attributes are not applicable to inline script tags as these attributes only affect external scripts linked via the src attribute. Inline scripts are executed immediately where they are located in the HTML.

    How do browser support and compatibility impact the use of async and defer attributes?

    Browser support and compatibility can impact the effective use of async and defer attributes. While most modern browsers support both, there may be inconsistencies or bugs in older browsers. Checking current browser support for these attributes is recommended.

    How do async and defer attributes contribute to SEO and page speed?

    Both async and defer attributes can improve page load speed by altering how JavaScript is loaded and executed. Faster page load times contribute positively to SEO as they enhance the user experience and can lead to higher rankings in search engine results pages.

    Szymon Soppa Web Developer
    Szymon Soppa Curiosum Founder & CEO

    Read more
    on #curiosum blog

    Bringing SOLID to Elixir

    Bringing SOLID to Elixir

    The SOLID principles, originally designed for object-oriented programming, can also be adapted effectively to functional programming languages like Elixir. Read how to apply it to create more maintainable, scalable, and adaptable software systems.