DEV Community

Cover image for Async vs Defer in JavaScript: Which is Better?πŸ€”
Fidal Mathew
Fidal Mathew

Posted on

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>
Enter fullscreen mode Exit fullscreen mode

Here's how HTML parsing and script execution takes place

default

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>
Enter fullscreen mode Exit fullscreen mode

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.

async

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>
Enter fullscreen mode Exit fullscreen mode

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.

defer

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! πŸ˜ƒ

Connect with me on-

Top comments (22)

Collapse
 
efpage profile image
Eckehard

As far as I know modern browsers use a preload scanner, so they start loading all scripts before HTML is parsed.

Anyway, things get interesting with ES6-modules that depend on other modules. I suppose it would make sense to put those dependencies in the head of your HTML file, even if they are not needed in the main context?

Collapse
 
joelbonetr profile image
JoelBonetR πŸ₯‡ • Edited

If you use a framework (or have enough patience using bundlers to customize uour own stuff) they manage "chunks" so each "route" gets what it needs and nothing else. It's possible to dynamically import stuff as well (e.g. Next/dynamic in Next JS as example, you can find vanilla examples online for that as well).

When loading scripts in HTML one can also create the script (html tag) dynamically and inject it to the DOM using the classic "appendchild" approach, meaning that you can have them load "on demand".

As @efpage well said, modern browsers have a preload scanner, the post don't fight the browser preload scanner is worth reading.
PD: you can manually add preload link tags for older browsers to use or to control the preload for different reasons.

Lastly and regarding the conclusions, it usually doesn't really matter that much which one you choose because both achieve the goal of not blocking the process, and you should wait for window load event (so everything has loaded) anyway shall you require it in tour scripts.

Cheers!

Collapse
 
dannyengelman profile image
Danny Engelman • Edited

Lastly and regarding the conclusions, it usually doesn't really matter that much which one you choose

With Web Components (eg: <my-component) it does matter because the native connectedCallback fires on the opening tag. Not using async or defer could be a better choice

Dev.to post: Web Component developers do not connect with the connectedCallback (yet)

Thread Thread
 
efpage profile image
Eckehard

The topic seems to be quite conplex, so I would tend to choose the most simple and robust approach. Just.... what are the consequences?

Fetching scripts and possibly executing them early could make your app feel more "snappy" and responsive, though in most cases I suppose the differences will be in the range of 200 ms or so, but the more important thing for me: Will it be recognized by the user?

ItΒ΄s worth to recap what a browser really does behind the scenes. See this great post on logrocket. Building the DOM is only one step, but there are multiple steps to be done, before a page is rendered. So, anything done before first render may delay the FCP, but will lead to a consistent result.

But what happens, if you wait for DOMContentLoaded? Will actions done in the event it still be included in the first render cycle, or will it cause a new one? If the content changes, you will possibly get a layour shift, so the content is rendered and just rerendered with a different layout, which looks not great.

IΒ΄m really not sure how to deal with this topic, expecially on large sites.

Thread Thread
 
joelbonetr profile image
JoelBonetR πŸ₯‡

A complex topic indeed. I'd analyse each use-case individually as there is no golden rule here, profile your large app so you can see what is blocking you. I've seen companies spending monies in thousands trying to optimise the wrong thing.

@dannyengelman using web components you need to first introduce an unknown tag into the DOM just to tell the browser what it is afterwards.
If you analyse it, it's no different than creating and injecting an HTML tag into the DOM from a script, or adding some feature to a given selected HTMLElement.

By that I mean that you are in control of this "afterwards" just like in any other script; you can also use async/defer and inside your script, wait for the proper event, then define your web component/s, and the result would be the same I assume.

Thread Thread
 
dannyengelman profile image
Danny Engelman • Edited

@dannyengelman using web components you need to first introduce an unknown tag into the DOM just to tell the browser what it is afterwards.
If you analyse it, it's no different than creating and injecting an HTML tag into the DOM from a script, or adding some feature to a given selected HTMLElement.

You are wrong here; you can use customElements.define before DOM is parsed.

This can easily be checked with element instanceOf HTMLElement

Its just that 89 out of a 100 developers do not know/do this. They fall into the connectedCallback trap and never investigate WHY their code doesn't work, and whack on async or defer thinking they solved the problem.

So Web Components are totally different from (oldskool) create-DOM-after-DOM-is-parsed scripts.

  1. Define Web Components early (before DOM is parsed) for all GUI stuff.
  2. Define Web Components late for all stuff that can wait (like the oldskool way)

Note: 1. can be two stages, like with icons: define the GUI ASAP, add interactivity later

Thread Thread
 
efpage profile image
Eckehard

This can easily be checked with element instanceOf HTMLElement

This just means that the code is available in the DOM. I suppose it will be executed when HTML is parsed which is not much different from executing a script somewhere inmiddle of your HTML code.

Anyway, this could be an advantage as HTML expression is usually paused as long as scripts are executed, but I suppose the differences will be minor.

Thread Thread
 
dannyengelman profile image
Danny Engelman

Difference is major when GUI Web Components are created with render blocking and inlined <script> in the <head>; then get enhanced to full interactive GUI after DOMContentLoaded
Inline the GUI required CSS as well (I mean bare CSS, not Tailwind) and the first HTML page should be 10 to 15 KB at the most... Eat that Vue,React.

Thread Thread
 
efpage profile image
Eckehard

I suppose, Tailwind (or any CSS in JS solution) will give another twist to this story, but this possibly would fill a complete post. Anyway, an interesting story...

Thread Thread
 
dannyengelman profile image
Danny Engelman

I said not to use Tailwind. That's a 479 Kb Gzipped download.

Do everything (for your primary GUI) native and in one HTML file, then PWA

Thread Thread
 
efpage profile image
Eckehard

Sorry this was a misunderstanding. Even if you do not use a bulky package like tailwind, any JS that manipulates global CSS might cause strange effects like Layout shifts and unexpected delays. But this would fill another post I suppose.

Collapse
 
fidalmathew profile image
Fidal Mathew

Thanks for sharing! Really insightful!!

Collapse
 
tzdesign profile image
Tobi

Use qwik.

This will do all the right things with the js.

Collapse
 
dagnelies profile image
Arnaud Dagnelies • Edited

I find the article misleading because it's not "vs". You can use both defer and async together, they don't exclude each other since they are unrelated. Defer is to wait for the page dom first, async is when other scripts don't need to wait for it.

Collapse
 
santoshkori profile image
Santosh Kori

Thanks for the visual differences. it easy to understand. I really appreciate

Collapse
 
emmykolic profile image
Emmanuel C. Okolie

Nice One Bro!

Collapse
 
adderek profile image
Maciej WakuΕ‚a

Pictures are nice. One should also know that browser does much more behind the scenes, that v8/gecko is single threaded but it's i/o is multithreaded, and lastly the impact onto the server (and how many requests can be done in parallel). Next step is http/2.0 multiplexing, tcp/IP topics (but also quic over tcp/udp), load balancing, cdn, cookies and serverside sessions, race conditions and effects if not done correctly. That is where the fun and complex stuff starts :)
Great article though for less experienced front-end devs :)

Collapse
 
sudouken profile image
Matthew

This article is a great overview. For a deeper dive, particularly into the DOMContentLoaded event check out this article:
javascript.info/script-async-defer

Collapse
 
manalu28 profile image
Rupinda Manalu

terimakasih atas ilmunya, saya baru mengetahui adanya defer.

Collapse
 
ayoubkhan558 profile image
Muhammad Ayoub Khan

Informative :)

Collapse
 
musfiquahaque profile image
Musfiqua haque

It is a mind-blowing article because I don't know about deferring previously. From there I understand the difference and also when I need to use deffer and async.
Thanks a lot.

Collapse
 
akashj2342 profile image
Akash

How to do same in react?