Skip to main content

How does "defer" differ from "async" in <script>?

The problem that defer and async solve

When the browser encounters the tag:

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

by default it:

  1. Stops parsing the HTML,
  2. Loads script.js,
  3. Executes it,
  4. Only then continues building the DOM.

This blocks the page's render, so the user sees a "blank screen" until the JS loads. That's why the defer and async attributes appeared, to avoid blocking HTML parsing.


defer

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

How it works:

  1. The script loads in parallel with the HTML (asynchronously).
  2. But it executes only after the HTML has fully finished parsing, that is, once the DOM is ready, but before the DOMContentLoaded event.
  3. Scripts with defer execute in the order they're listed in the HTML.

It's great for an application's "main" scripts (for example, main.js, vendor.js).

Example:

javascript
<script src="a.js" defer></script> <script src="b.js" defer></script>

Both load in parallel first, but they execute strictly in order: a.js then b.js, after the DOM is built.


async

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

How it works:

  1. The script loads in parallel with the HTML (like defer),
  2. But it executes immediately after it loads, even if the HTML hasn't finished parsing yet.
  3. Scripts with async execute in an unpredictable order, depending on which one finishes loading first.

It's suited for independent scripts (for example, analytics, ads, metrics).

Example:

javascript
<script src="a.js" async></script> <script src="b.js" async></script>

b.js can execute before a.js if it loads faster, even if it appears lower in the HTML.


Comparing defer and async

Propertydeferasync
Script loadingAsynchronous (in parallel with HTML)Asynchronous
ExecutionAfter HTML fully finishes parsingRight after loading
Execution orderPreservedNot guaranteed
Blocks HTML parsingNoNo
DOMContentLoaded eventWaits for all defer scripts to runDoesn't wait
Typical scenariosThe site's main logicExternal trackers, ads

A visual example

javascript
<!-- HTML is being parsed... --> <script src="main.js" defer></script> <script src="analytics.js" async></script>

The process:

StageWhat happens
1The browser starts parsing the HTML
2Both scripts load simultaneously
3analytics.js (async) loads faster, so it executes right away
4The HTML finishes parsing
5Then main.js (defer) executes
6Then DOMContentLoaded fires

Conclusions

AttributeWhen to use it
deferFor the site's main JS code that depends on the DOM (for example, initializing the interface)
asyncFor independent scripts (analytics, metrics, ads)
No attributesOnly when you need to block HTML parsing (rarely needed)

A tip

If you use a modern bundler (Next.js, Vite, Webpack), it already adds defer to <script> tags in head for you, so in modern applications this is already the default best practice.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.