How to Handle JavaScript Non-Blocking Loading with `async` and `defer`

Use the async attribute for independent scripts that don't touch the DOM and the defer attribute for scripts that require the full document structure, ensuring both download in parallel without blocking the HTML parser.

By default, browsers encounter a render-blocking behavior when loading JavaScript: the parser stops building the DOM, fetches the script, executes it, and only then resumes parsing. This process delays First Contentful Paint, particularly on mobile networks. The Front-End Checklist repository by thedaviddias explicitly recommends loading JavaScript asynchronously using these attributes to improve page performance metrics.

Understanding Render-Blocking Behavior

When the browser parser hits a standard <script> tag without any attributes, it immediately pauses HTML parsing to fetch and execute the code. This synchronous loading increases time-to-interactive and can degrade user experience on slow connections. Modern HTML specifications provide async and defer to eliminate this bottleneck, allowing scripts to download concurrently while the document continues parsing.

Using the async Attribute

The async attribute downloads the script file in parallel with HTML parsing and executes it immediately after the download completes, even if the parser is still processing the document.

This approach suits small, self-contained scripts such as analytics trackers or feature-detection utilities that do not depend on DOM elements or other scripts. Because execution order is not guaranteed, avoid async for scripts with dependencies.

<script src="https://example.com/analytics.js" async></script>

Important: The async attribute requires an external script with a src attribute and cannot be used on inline scripts.

Using the defer Attribute

The defer attribute also downloads the script file in parallel with parsing, but it delays execution until after the entire document has been parsed, just before the DOMContentLoaded event fires.

This method preserves the execution order of multiple deferred scripts and guarantees the DOM is fully constructed when the script runs. Use defer for main application bundles, frameworks, or any code that queries or manipulates DOM elements.

<script src="js/app.bundle.js" defer></script>

Comparing async vs defer

Attribute Download Timing Execution Timing Best For
async Parallel with parsing Immediately after download (pauses parser) Independent scripts (analytics, ads)
defer Parallel with parsing After document parse, before DOMContentLoaded DOM-dependent scripts, ordered execution

Scripts marked with defer maintain their relative execution sequence, while async scripts execute as soon as they arrive, potentially out of order.

Practical Implementation Strategies

For applications using multiple scripts with different loading requirements, mix strategies carefully. Place independent utilities with async and core application code with defer to ensure dependencies resolve correctly.

<!-- Independent utility library (doesn't touch the DOM) -->
<script src="js/utility.js" async></script>

<!-- Core framework that must execute after the DOM is built -->
<script src="js/framework.js" defer></script>

<!-- Application code that depends on the framework -->
<script src="js/main.js" defer></script>

For legacy browser support (very old browsers that do not recognize these attributes), dynamically inject scripts as a fallback:

var script = document.createElement('script');
script.src = 'js/app.bundle.js';
script.defer = true;
document.head.appendChild(script);

Front-End Checklist Recommendation

According to the source code in README.md at line 532, the Front-End Checklist identifies "JavaScript files are loaded asynchronously using async or deferred using defer" as a medium-priority performance item. Following this guideline reduces render-blocking resources, improves First Contentful Paint scores, and aligns with modern web performance best practices.

Summary

  • Render-blocking occurs when standard scripts pause HTML parsing during download and execution.
  • Use async for external scripts that don't require the DOM or specific execution order.
  • Use defer for external scripts that need the full DOM or must execute in sequence.
  • Both attributes require the src attribute and do not work on inline scripts.
  • The thedaviddias/Front-End-Checklist explicitly recommends these attributes at README.md line 532 for optimal loading performance.

Frequently Asked Questions

Can I use async or defer on inline scripts?

No. Both attributes are only valid on external scripts that include a src attribute. Inline scripts without a src cannot be loaded asynchronously or deferred using these HTML attributes.

When should I choose defer over async?

Choose defer when your script needs to access DOM elements, relies on other scripts loading first, or requires predictable execution order. Choose async for standalone scripts like analytics or tracking pixels that execute independently of the page structure.

What happens to deferred scripts when the document finishes parsing?

Deferred scripts execute after the HTML parser completes but before the DOMContentLoaded event fires. This timing ensures the full DOM is available while still allowing the script to run before sub-resource loading completes.

How do I handle browsers that don't support async or defer?

For very old browsers that lack support, dynamically create script elements using JavaScript and set the defer or async properties before appending them to the document head. This method provides equivalent non-blocking behavior in modern browsers while ensuring functionality in legacy environments.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →