Async & Defer
By default, HTML is parsed from top to bottom.
When the browser encounters an <img> tag, it starts downloading the image but continues parsing the rest of the HTML.
However, when it encounters a <script> tag:
The browser pauses HTML parsing, downloads the JavaScript, executes it, and only then continues parsing the HTML.
This behavior is called blocking.
The async and defer attributes allow us to modify how scripts are loaded and executed.
Async
With async:
- HTML parsing continues while the JavaScript file is downloading
- As soon as the JavaScript finishes downloading, HTML parsing pauses during execution
- The script executes immediately
- Then HTML parsing resumes
Key idea:
Async scripts run as soon as they’re ready, not in order
This means:
- execution order is not guaranteed and may differ from script order in the HTML
- best for scripts that are independent (e.g. analytics)
Defer
With defer:
- HTML parsing continues while the JavaScript file downloads
- The script does not execute immediately after downloading
- Instead, it waits until all HTML parsing is complete
- Then scripts execute in the order they appear in the document
Key idea:
Defer scripts run after the DOM is fully built

Why This Matters
Some developers choose to always use defer when loading scripts because:
- scripts download early (better performance)
- scripts run late (after the DOM exists)
- execution order is preserved
This removes the need to place <script> tags at the bottom of the <body>. (See below for common use cases for async).
| Feature | Async | Defer |
|---|---|---|
| Blocks HTML parsing | Only during execution | Never during parsing |
| Execution timing | As soon as ready | After HTML parsing |
| Order guaranteed | ❌ No | ✅ Yes |
One important constraint
defer only works for external scripts and is ignored on inline scripts:
<script src="script.js" defer></script>Not:
<script defer>
// inline JS
</script>Good Use Cases for Async
Use async for scripts that are independent of your application logic and do not rely on execution order, such as analytics, ads, and third-party widgets.
Use async when the script:
- does not depend on other scripts
- does not need the DOM to be fully ready
- can run whenever it finishes downloading
Examples of when to use Async
Analytics / Tracking
<script async src="https://www.googletagmanager.com/gtag/js"></script>Why:
- does not affect UI
- does not depend on your app logic
- order doesn’t matter
Ads / Ad networks
<script async src="https://ads.network.com/script.js"></script>Why:
- completely independent
- performance matters (don’t block page load)
- execution timing is not critical
Social media widgets
<script async src="https://platform.twitter.com/widgets.js"></script>Why:
- enhances the page, not required for core functionality
- doesn’t need to run in a specific order
Feature scripts that don’t depend on the DOM
Example: logging, metrics, or background tasks
<script async src="/js/logger.js"></script>Why:
- not tied to specific elements
- can run anytime
Independent micro-features
Example: a script that enhances something optional like:
- A/B testing
- heatmaps
- feedback tools
<script async src="/js/heatmap.js"></script>Why:
- does not need to coordinate with your main app
- safe to run whenever
When NOT to use async
When order matters
<script async src="lib.js"></script>
<script async src="app.js"></script>Problem:
- app.js might run before lib.js
When scripts depends on the DOM
document.querySelector(".btn")If the DOM isn’t ready yet → null
When scripts depend on each other
Example:
// app.js depends on helper.jsAsync can break this.
To decide, ask yourself:
“If this script runs early, late, or out of order… will anything break?”
- Yes → use defer
- No → async is safe
| Use case | async | defer |
|---|---|---|
| Analytics | ✅ | ❌ |
| Ads | ✅ | ❌ |
| UI logic | ❌ | ✅ |
| DOM manipulation | ❌ | ✅ |
| Script dependencies | ❌ | ✅ |