Back
Web Fundamentals

Script Loading: async vs defer

On this page

easyRendering & Browser Architecture

Script Loading: async vs defer

TL;DRRegular script blocks parsing • async = parallel + immediate execution (unordered) • defer = parallel + after parsing (ordered)
Very High Signal
Google
Meta
Atlassian
Netflix
30-Second Answerstart every interview with this

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.

Parser encounters <script>
Regular: Block & Execute
async: Download parallel → Execute ASAP
defer: Download parallel → Execute after parse (ordered)
type=module: Behaves like defer by default

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.

index.htmlhtml
<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.

index.htmlhtml
<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.

index.htmlhtml
<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.

index.htmlhtml
<script type="module" src="app.js"></script>
<!-- async module -->
<script type="module" async src="utils.js"></script>
PropertyRegular <script>asyncdefer
BehaviorBlocks HTML parsingNon-blocking downloadNon-blocking download
Best ForCritical inline config or rare blocking needsAnalytics, ads, independent third-party scriptsApplication code, vendor libraries, DOM-dependent scripts
Dom ReadyNo guaranteeMay run before DOM is parsedYes (DOM is fully parsed)
Execution TimingImmediately after downloadAs soon as downloadedAfter HTML parsing completes
Order GuaranteedYes (document order)NoYes (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
Key Takeaways
  • ✓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?

Related web fundamentals topics

Continue with closely related browser and frontend engineering concepts.

Critical Rendering PathEvent Loop: Understanding JavaScript Execution ModelJavaScript Module Systems: CJS vs ESM vs UMDDynamic Module Loading: import() FunctionImport on Interaction: Load When User InteractsImport on Visibility: Lazy Loading with IntersectionObserver
Previous TopicCritical Rendering PathNext Topic Event Loop: Understanding JavaScript Execution Model