Script Loading: async vs defer
Script loading attributes control parser blocking, download behavior, and execution timing. A plain <script> blocks HTML parsing. async downloads in parallel and executes as soon as ready (no order guarantee). defer downloads in parallel and executes after HTML parsing completes, in document order. type=module scripts are deferred by default.
The HTML parser is the main builder. A regular script stops the entire crew until it finishes. async workers arrive independently and start working the moment they show up. defer workers arrive early but wait politely until the main structure (HTML) is complete before starting, in the order they were hired.
1Regular Script (No Attribute)
Blocks HTML parsing completely. The browser fetches and executes the script immediately before continuing to parse the rest of the document. Use only when you truly need blocking behavior.
<script src="app.js"></script> <!-- parser-blocking -->
2The async Attribute
Downloads in parallel while parsing continues. Executes as soon as the script is ready — order is not guaranteed. Can still interrupt parsing when it runs. Best for independent scripts like analytics or ads.
<script async src="analytics.js"></script>
3The defer Attribute
Downloads in parallel. Execution is delayed until HTML parsing is complete. Multiple defer scripts execute in document order. Ideal default for most application code that needs the DOM or predictable ordering.
<script defer src="vendor.js"></script> <script defer src="app.js"></script>
4Module Scripts (type=module)
Modern ES modules are deferred by default. They download in parallel and execute after parsing. Adding async makes them execute as soon as ready (like classic async). defer attribute has no additional effect.
<script type="module" src="app.js"></script> <!-- async module --> <script type="module" async src="utils.js"></script>
| Property | Regular <script> | async | defer |
|---|---|---|---|
| Behavior | Blocks HTML parsing | Non-blocking download | Non-blocking download |
| Best For | Critical inline config or rare blocking needs | Analytics, ads, independent third-party scripts | Application code, vendor libraries, DOM-dependent scripts |
| Dom Ready | No guarantee | May run before DOM is parsed | Yes (DOM is fully parsed) |
| Execution Timing | Immediately after download | As soon as downloaded | After HTML parsing completes |
| Order Guaranteed | Yes (document order) | No | Yes (document order) |
Regular <script>
Behavior
Blocks HTML parsing
Best For
Critical inline config or rare blocking needs
Dom Ready
No guarantee
Execution Timing
Immediately after download
Order Guaranteed
Yes (document order)
async
Behavior
Non-blocking download
Best For
Analytics, ads, independent third-party scripts
Dom Ready
May run before DOM is parsed
Execution Timing
As soon as downloaded
Order Guaranteed
No
defer
Behavior
Non-blocking download
Best For
Application code, vendor libraries, DOM-dependent scripts
Dom Ready
Yes (DOM is fully parsed)
Execution Timing
After HTML parsing completes
Order Guaranteed
Yes (document order)
Common questions
- ›“What is the difference between async and defer?”
- ›“When would you use async vs defer scripts?”
- ›“How do script attributes affect the Critical Rendering Path?”
- ›“Explain script loading behavior for type=module”
What interviewers look for
- Clear understanding of parser-blocking vs non-blocking
- Knowledge of execution order and DOM readiness
- Ability to choose the right attribute based on use case
- Awareness that modules are deferred by default
Short answer (60 sec)
Regular scripts block parsing. async downloads in parallel and runs as soon as ready (unordered). defer downloads in parallel and runs after parsing in document order. Use defer for most app scripts and async for independent third-party code.
Detailed answer (senior level)
The key differences are parser blocking, execution timing, and ordering. A plain script stops the parser. async scripts can execute before parsing finishes and have no order guarantee. defer scripts preserve order and run after the DOM is parsed (before DOMContentLoaded). Module scripts behave like defer by default. Senior answers also mention how these affect First Contentful Paint and DOMContentLoaded timing.
- Using async for dependent scripts (order not guaranteed)
- Forgetting that async scripts can run before the DOM is parsed
- Adding defer to type=module scripts (already deferred)
- Using blocking scripts for non-critical third-party code
- Assuming all scripts wait for the DOM
- ✓defer is the safest default for most application JavaScript
- ✓async is ideal for independent scripts (analytics, ads)
- ✓Regular scripts should be used sparingly — only when blocking is required
- ✓type=module scripts are deferred by default
- ✓Choose based on: Do you need order? Do you need the DOM? Is the script independent?