async vs defer in JavaScript: How Script Loading Really Works
How Script Loading Really Works
If you’ve ever added JavaScript to an HTML page, you’ve probably written something like this:
<script src="script.js"></script>
But modern JavaScript gives you two powerful attributes:
asyncdefer
They change how scripts load and execute, and using the wrong one can break your page.
In this article, you’ll learn:
how browsers load scripts by default
what
asyncdoeswhat
deferdoeskey differences between them
when to use each
common mistakes
Let’s start with the default behavior.
How Browsers Load JavaScript by Default
When the browser encounters this:
<script src="app.js"></script>
It does three things in order:
Stops parsing HTML
Downloads the JavaScript file
Executes the JavaScript
Resumes parsing HTML
This is called render-blocking.
Problem with Default Behavior
Slows down page rendering
Bad for performance
Especially harmful for large scripts
This is where async and defer help.
What Is async?
The async attribute tells the browser:
“Download this script in parallel, and execute it as soon as it’s ready.”
<script src="async.js" async></script>
How async Works
HTML parsing continues
Script downloads in parallel
HTML parsing pauses when the script finishes downloading
Script executes immediately
Execution time is not predictable.
Example
<script src="analytics.js" async></script>
This is perfect for scripts that:
do not depend on DOM
do not depend on other scripts
Key Characteristics of async
✔ Downloads in parallel
✔ Executes immediately after download
❌ Execution order not guaranteed
❌ Can interrupt HTML parsing
What Is defer?
The defer attribute tells the browser:
“Download this script in parallel, but execute it after HTML parsing is complete.”
<script src="defer.js" defer></script>
How defer Works
HTML parsing continues
Script downloads in parallel
Script execution waits
Executes after DOM is fully built
Example
<script src="main.js" defer></script>
This is ideal for scripts that:
manipulate the DOM
depend on HTML elements
Key Characteristics of defer
✔ Downloads in parallel
✔ Executes after HTML parsing
✔ Execution order is preserved
✔ Safe for DOM access
async vs defer: Side-by-Side Comparison
| Feature | async | defer |
| HTML parsing | Pauses during execution | Never pauses |
| Download | Parallel | Parallel |
| Execution time | As soon as ready | After DOM loaded |
| Order preserved | ❌ No | ✔ Yes |
| DOM safe | ❌ Not guaranteed | ✔ Yes |
| Best for | Independent scripts | App logic |
Execution Order Example
<script src="a.js" async></script>
<script src="b.js" async></script>
Execution order:
a.jsorb.js(depends on download speed)
<script src="a.js" defer></script>
<script src="b.js" defer></script>
Execution order:
a.jsb.js
Always in order.
When Should You Use async?
Use async when the script:
✔ Is independent
✔ Does not access DOM
✔ Does not depend on other scripts
Common Use Cases
Analytics
Ads
Tracking scripts
<script src="google-analytics.js" async></script>
When Should You Use defer?
Use defer when the script:
✔ Needs DOM access
✔ Depends on other scripts
✔ Is part of your application logic
Common Use Cases
Main JS files
UI logic
Event handlers
<script src="app.js" defer></script>
What About Scripts at the Bottom of <body>?
Old approach:
<script src="app.js"></script>
</body>
Modern approach:
<script src="app.js" defer></script>
✔ Cleaner
✔ Better performance
✔ Recommended
async and defer with Inline Scripts
They do not work with inline scripts.
❌ This does nothing:
<script async>
console.log("Hello");
</script>
They only work with external scripts.
Common Mistakes
❌ Using async for dependent scripts
<script src="lib.js" async></script>
<script src="app.js" async></script>
app.js may run before lib.js.
❌ Accessing DOM with async
document.getElementById("btn"); // may be null
❌ Mixing async and defer carelessly
Stick to one strategy.
Best Practices
✔ Use defer for most scripts
✔ Use async only when truly independent
✔ Avoid default blocking scripts
✔ Never rely on async execution order
✔ Prefer defer over placing scripts at bottom
Mental Model to Remember
Default: Stop → Download → Execute
Async: Download → Execute ASAP
Defer: Download → Wait → Execute after DOM