Question

HTML Script async and defer Attributes Explained

htmljavascript

Question

You have two external JavaScript files near the end of the <body>: jQuery loaded from a CDN, followed by a local script that depends on jQuery.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="/js/app.js"></script>

What are the performance and behavior differences between leaving these scripts at the bottom of the page and moving them into the <head> with async or defer?

In particular:

  • Is adding async to scripts at the end of <body> useful?
  • Do scripts in <head> begin downloading while the page is being parsed?
  • Does <script defer src="..."></script> in <head> behave like placing scripts before </body>?
  • If two scripts use async, can they download concurrently, and does their execution order become unreliable?
  • What should be used when the second script depends on the first?
  • How should older browsers be considered?

Short Answer

By the end of this page, you will understand when browsers download and run external scripts, how async and defer affect HTML parsing, and why dependent files such as jQuery and an application script should usually use defer rather than async.

Concept

A normal external <script> affects the browser in two separate ways:

  1. Downloading: fetching the JavaScript file from a server.
  2. Executing: running the JavaScript code.

Without attributes, a classic script blocks HTML parsing when the parser reaches it. The browser normally downloads the script, executes it, and only then continues reading the HTML below it.

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

The async and defer attributes allow a browser to download an external script while it continues parsing the HTML. Their crucial difference is when the downloaded script executes and whether source order is preserved.

  • async: execute as soon as each file finishes downloading. Order is not guaranteed.
  • defer: execute after HTML parsing finishes. Deferred classic scripts execute in document order.

This matters because many applications have dependencies. If app.js calls jQuery's $, jQuery must execute first. async is unsafe for that pair because app.js could finish downloading and run before jQuery.

These attributes are not something to postpone until "HTML5 browsers" are available. They are established browser features, and modern browser support is broad. However, test any browser versions your audience must support. Older browsers may ignore unsupported attributes, which can change the fallback behavior.

Mental Model

Imagine the HTML parser is a reader moving through a recipe book, and each script is a task the reader must perform.

  • A normal script says: “Stop reading, collect the ingredient, use it now, then continue.”
  • An async script says: “Ask someone to fetch the ingredient while reading continues. The instant it arrives, stop and use it.” The ingredients may arrive in any order.
  • A defer script says: “Ask someone to fetch the ingredient while reading continues. After the entire recipe has been read, use the ingredients in the listed order.”

For files with dependencies, defer is like following numbered recipe steps. async is suitable only when each task is independent.

Take Quiz

Syntax and Examples

A normal script blocks parsing at the point where it appears:

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

Use defer for scripts that need a predictable order or need the document to be fully parsed:

<head>
  <script defer src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
  <script defer src="/js/app.js"></script>
</head>

The browser can fetch both files while it parses the page. Once parsing is complete, it runs jQuery first and then app.js.

// app.js
$(function () {
  console.log("jQuery is available and the DOM is ready.");
});

Use async only for an independent script:

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

For example, analytics code often records page visits and does not provide functions that your application code immediately depends on. It can run whenever its download completes.

For classic external scripts, async and defer only have their special loading behavior when src is present. If both attributes are present, async takes precedence.

Step by Step Execution

Consider a page with two dependent scripts in the document <head>:

<head>
  <script defer src="/js/library.js"></script>
  <script defer src="/js/app.js"></script>
</head>
<body>
  <h1>Account</h1>
</body>
// library.js
window.formatName = function (name) {
  return name.toUpperCase();
};
// app.js
console.log(formatName("Ada"));

Execution sequence:

  1. The browser starts parsing the <head>.
  2. It discovers library.js and starts downloading it without pausing HTML parsing.
  3. It discovers app.js and can also start downloading it.
  4. The browser continues parsing the <body> and creates the <h1> element.
  5. After HTML parsing has completed, the browser executes library.js.
  6. It then executes app.js, even if app.js happened to download first.
  7. The console prints ADA.

Now replace defer with async:

<script async src="/js/library.js"></script>
<script async src="/js/app.js"></script>

Both downloads may overlap, but whichever completes first executes first. If app.js executes before library.js, formatName does not exist yet and the code fails.

Real World Use Cases

  • Application bundles with dependencies: Load a vendor bundle before an application bundle using defer so execution remains ordered.
  • Page-specific user interface code: Defer code that attaches click handlers or reads page elements, because the HTML will be parsed before it runs.
  • Analytics and measurement: Use async when a third-party script is independent of your app's startup code.
  • Advertisements and widgets: Independent third-party integrations often use async, although their impact on performance and privacy should still be evaluated.
  • Static sites: Put deferred site JavaScript in <head> so downloads can start early while the browser builds the page.
  • Legacy jQuery sites: Load jQuery first and a script that uses $ second with defer, or retain normal scripts near the end of <body>. Do not mark both as async.
Take Quiz

Real Codebase Usage

In a real project, developers choose a loading strategy based on dependencies and when code is needed.

Ordered application scripts

<head>
  <script defer src="/assets/vendor.js"></script>
  <script defer src="/assets/app.js"></script>
</head>

This is common when app.js depends on code in vendor.js.

Independent third-party script

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

Do not write application startup code that assumes this script has loaded immediately. If an integration requires a callback or event, use the provider's documented loading API.

DOM initialization after deferred code

Deferred scripts run after document parsing, so they can usually select elements directly:

const saveButton = document.querySelector("#save-button");

if (saveButton) {
  saveButton.addEventListener("click", saveProfile);
}

The if is a guard clause: it lets the same script work on pages that do not contain that button.

Modern module scripts

For new applications, module scripts are often used:

<script type="module" src="/js/app.js"></script>

Module scripts are deferred by default. Their imports describe dependencies explicitly, which is usually more maintainable than manually ordering many classic script tags.

Common Mistakes

Marking dependent files as async

Broken example:

<script async src="/js/jquery.js"></script>
<script async src="/js/app.js"></script>
// app.js
$("#menu").show();

app.js may run before jQuery is available. Use defer in source order instead:

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

Assuming async means “runs after the page loads”

It does not. An async script runs as soon as it is ready, possibly before the HTML parser reaches elements later in the page. Do not rely on DOM elements being present unless your code waits for them or the script is deferred.

Assuming defer and bottom-of-body scripts are identical

They are similar in that both avoid blocking most visible HTML parsing. But they are not identical:

  • Deferred scripts in <head> can be discovered and downloaded earlier.
  • Deferred scripts execute after the document has finished parsing.
  • Normal scripts near </body> still block parsing when the browser reaches them.

Using defer on an inline classic script

<script defer>
  console.log("This does not become deferred in the same useful way.");
</script>

Use defer with an external src script. Place inline initialization after the deferred external script only when you know the required code has executed, or keep the initialization in the deferred external file.

Adding both async and defer expecting both benefits

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

For classic scripts, treat this as async: execution order is not guaranteed. Choose the one that matches your requirements.

Forgetting cache and network effects

async and defer improve how downloading overlaps with parsing, but they do not guarantee a faster page in every measurement. File size, caching, server speed, and third-party scripts still matter.

Comparisons

Script formDownload timingExecution timingPreserves source order?Good for
<script src="...">When parser reaches itImmediately after downloadYesSmall scripts needed at that exact point
Normal script near </body>Late in parsingImmediately after downloadYesOlder patterns; simple dependent scripts
<script defer src="...">During HTML parsingAfter parsing completesYes, among deferred classic scriptsApplication code and dependent files
<script async src="...">During HTML parsingAs soon as each download completesNoIndependent analytics or widgets
<script type="module" src="...">During HTML parsingDeferred by defaultImports manage dependenciesModern JavaScript applications

For the jQuery-plus-application scenario:

ApproachSafe dependency order?Can start downloads early?
Two normal scripts before </body>YesUsually later
Two async scriptsNoYes
Two defer scripts in <head>YesYes
Take Quiz

Cheat Sheet

<!-- Normal: parser blocks here -->
<script src="/js/app.js"></script>

<!-- Ordered, runs after HTML parsing -->
<script defer src="/js/library.js"></script>
<script defer src="/js/app.js"></script>

<!-- Independent, runs whenever ready -->
<script async src="/js/analytics.js"></script>
  • Use defer for classic scripts that depend on each other.
  • Put deferred scripts in source order: dependency first, dependent script second.
  • Use async only when the script is independent.
  • Multiple async scripts may download in parallel, but execution order is unpredictable.
  • Deferred external scripts download while HTML is parsed and execute after parsing completes.
  • A normal script at the bottom of <body> is ordered, but it is discovered later and still blocks when reached.
  • async takes precedence if both async and defer are present on a classic external script.
  • Test the browser versions you support; unsupported attributes may fall back to normal script behavior.

FAQ

Should I use async or defer for jQuery?

Use defer if another script uses jQuery. Put the jQuery tag before the script that depends on it.

Do async scripts download at the same time?

Browsers can fetch multiple resources concurrently, subject to network and browser scheduling. However, async does not guarantee simultaneous downloads or execution order.

Does defer preserve script order?

Yes. External classic scripts with defer execute in the order in which they appear in the document, after parsing finishes.

Does an async script wait for the DOM to be ready?

No. It executes as soon as it finishes downloading. The document may still be parsing.

Is putting scripts before </body> still valid?

Yes. It remains valid and preserves normal source order. defer in <head> is often preferable because downloads can begin earlier.

Does defer work only in HTML5?

No. It is not limited to HTML5. Support details vary for very old browsers, so use your project's browser-support policy and test where necessary.

Can I use defer and async together?

Do not use both to combine their behavior. For a classic external script, async wins, so ordering is not reliable.

What is the best default for a new site?

For non-module application JavaScript, defer is usually a strong default. For modern applications, type="module" is often appropriate because module scripts are deferred by default.

Take Quiz

Mini Project

Description

Build a small page that loads a utility library and application code without blocking HTML parsing. The application file uses a function from the library, demonstrating why ordered loading matters.

Goal

Load two dependent JavaScript files with defer and update a page element after parsing completes.

Requirements

Use two external JavaScript files named helpers.js and app.js. Load both files in the document <head> with defer. Make app.js call a function defined in helpers.js. Display a greeting inside an element with the ID message. Keep helpers.js before app.js in the HTML.

Take Quiz

Keep learning

Related questions

View more