Skip to main content

The async attribute in script

async is a <script> attribute that tells the browser to download the script asynchronously, in parallel with the HTML, and to execute it right after it arrives, without waiting for the DOM to be built or for other scripts. It is the fastest but also the least predictable way to include a script, because the execution order of the files is not guaranteed.

Theory

TL;DR

  • async downloads an external script in parallel with HTML parsing, and parsing is not stopped for the download.
  • As soon as the file has arrived it runs immediately, even if the HTML has not been fully read yet.
  • That execution can briefly interrupt the parsing of the page.
  • The order of several async scripts is arbitrary and depends on network speed.
  • async and defer only apply to external scripts with src; inline scripts ignore them.
  • Use async for independent code (analytics, ads, widgets) and defer for the main site logic.

Quick example

html
<head> <!-- independent script: downloads in the background and starts as soon as it is ready --> <script src="analytics.js" async></script> </head>

How a plain <script> works

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

What the browser does:

  1. Starts reading the HTML.
  2. Meets a <script>.
  3. Stops parsing the HTML.
  4. Downloads app.js.
  5. Executes app.js.
  6. Continues reading the HTML.

So a plain <script> blocks page loading until it has been executed.

What async does

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

Now:

  1. The browser keeps loading the HTML.
  2. In parallel it downloads app.js in the background.
  3. As soon as app.js has arrived, it executes it immediately, even if the HTML is not finished.

That is:

  • the download is asynchronous;
  • the execution is immediate;
  • the order relative to other scripts is not guaranteed.

Visually it looks like this:

text
HTML: |-----parsing-----|--------> JS: |---download---|execution|

HTML and JS are fetched in parallel, but JS execution can interrupt HTML parsing if the script finishes downloading first.

How it differs from defer

AttributeWhen the script runsOrderBlocks HTMLWhen to use
(no attribute)Immediately when metIn orderYesLegacy inline code
asyncRight after downloadRandomMay interruptIndependent scripts (analytics, ads)
deferAfter the DOM is builtIn orderNoThe main site code

The gist:

  • async means "run when you are ready, wait for nobody";
  • defer means "wait until the DOM is built, then run in order".

A combined property table:

Propertyasyncdefer
Downloads in parallel with HTMLYesYes
Runs as soon as it is downloadedYesNo
Waits for the DOM to be readyNoYes
Preserves script orderNoYes
Blocks HTML parsing while executingYes, it may interruptNo
Ideal forIndependent scripts (analytics, ads, widgets)The main site logic

Several async scripts

html
<script src="a.js" async></script> <script src="b.js" async></script>

They may execute in any order, depending on which file downloads first. So if b.js counts on globals defined by a.js, that pair will break sooner or later on a slow network.

There is another consequence: an async script can start before the markup element it needs exists. If the code touches the DOM, either switch to defer or wrap the work in a DOMContentLoaded handler.

Correct usage in <head>

async and defer work only for external scripts (src="..."). Inline ones (<script>...</script>) ignore these attributes.

An example of correct inclusion:

html
<head> <script src="vendor.js" async></script> <script src="main.js" defer></script> </head>

Here the analytics-like vendor.js is independent and can start at once, while main.js depends on the DOM and therefore runs after it has been built.

An easy way to remember: async means "download and run as fast as possible", defer means "download early, but wait until the DOM is ready".

Common mistakes

  • Putting async on scripts that depend on each other. The order is random and the dependency will break unexpectedly.
  • Touching the DOM from an async script. The element you need may not exist yet; use defer or wait for DOMContentLoaded.
  • Writing async on an inline script. Without src the attribute has no effect at all.
  • Assuming async never blocks the page. The download does not block, but the execution can interrupt HTML parsing.
  • Putting async on the main application bundle. It almost always depends on the DOM and on order, which is a job for defer.
  • Expecting DOMContentLoaded to wait for an async script. The event may fire before such a file has even downloaded.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.