The script tag's async and defer attributes. Difference between async and defer on script tag

The HTML element is used to embed or reference executable code; this is typically used to embed or refer to JavaScript code.

The element can also be used with other languages, such as WebGL "s GLSL shader programming language. Metadata content, Flow content, Phrasing content. Dynamic script such as text/javascript . None, both the starting and ending tag are mandatory. Any element that accepts metadata content , or any element that accepts phrasing content . None
Content categories
Permitted content
Tag omission
Permitted parents
Permitted ARIA roles
DOM interface
HTMLScriptElement

Attributes async HTML5

For classic scripts, if the async attribute is present, then the classic script will be fetched in parallel to parsing and evaluated as soon as it is available.

crossorigin Normal script elements pass minimal information to the window.onerror for scripts which do not pass the standard CORS checks. To allow error logging for sites which use a separate domain for static media, use this attribute. See CORS settings attributes for a more descriptive explanation of its valid arguments.

defer

This Boolean attribute is set to indicate to a browser that the script is meant to be executed after the document has been parsed, but before firing DOMContentLoaded .

Scripts with the defer attribute will prevent the DOMContentLoaded event from firing until the script has loaded and finished evaluating.

This attribute must not be used if the src attribute is absent (i.e. for inline scripts), in this case it would have no effect.

Examples Basic usage

These examples show how to import (an external) script using the element.

And the following examples show how to put (an inline) script inside the element.

alert("Hello World!");

Module fallback Browsers that support the module value for the type attribute ignore any script with a nomodule attribute. That enables you to use module scripts while also providing nomodule -marked fallback scripts for non-supporting browsers.
Specifications
Specification Status Comments
HTML Living Standard The definition of "" in that specification.
Living Standard
Specification Status Comments
Removed the charset attribute
HTML5
Specification Status Comments
Removed the charset attribute
Recommendation

The compatibility table in this page is generated from structured data. If you"d like to contribute to the data, please check out https://github.com/mdn/browser-compat-data and send us a pull request.

Update compatibility data on GitHub

Desktop Mobile Chrome Edge Firefox Internet Explorer Opera Safari Android webview Chrome for Android Firefox for Android Opera for Android Safari on iOS Samsung Internetscript async crossorigin defer integrity language

Deprecated Non-standard

nomodule

Experimental

referrerPolicy src text type type.module type: The version parameter of the type attribute

Non-standard

Chrome Full support 1Edge Full support 12Firefox Full support 1

Notes

Full support 1

Notes

Notes Starting in Firefox 4, inserting elements that have been created by calling document.createElement("script") no longer enforces execution in insertion order. This change lets Firefox properly abide by the specification. To make script-inserted external scripts execute in their insertion order, set .async=false on them.
IE Full support YesOpera Full support YesSafari Full support Yes
Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support YesOpera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesFirefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support Yes
Chrome Full support 30Edge Full support ≤18Firefox Full support 13IE No support NoOpera Full support 12Safari Full support Yes

Notes

Full support Yes

Notes

Notes The crossorigin attribute was implemented in WebKit in WebKit bug 81438.
WebView Android Full support YesChrome Android Full support YesFirefox Android Full support 14Opera Android?Safari iOS?Samsung Internet Android Full support Yes
Chrome Full support Yes

Notes

Full support Yes

Notes

Notes Chromium Issue #611136, Chromium Issue #874749
Edge Full support 12Firefox Full support 3.5

Notes

Full support 3.5

Notes

Notes Since Firefox 3.6, the defer attribute is ignored on scripts that don"t have the src attribute. However, in Firefox 3.5 even inline scripts are deferred if the defer attribute is set.
IE Full support 10

Notes

Full support 10

Notes

Notes In versions prior to Internet Explorer 10, it implemented defer by a proprietary specification. Since version 10 it conforms to the W3C specification.
Opera Full support Yes

Notes

Full support Yes

Notes

Notes Chromium Issue #611136, Chromium Issue #874749
Safari Full support YesWebView Android Full support Yes

Notes

Full support Yes

Notes

Notes WebView does not defer scripts with the defer attribute when the page is served as XHTML (application/xhtml+xml) - Chromium Issue #611136 , Chromium Issue #874749
Chrome Android Full support Yes

Notes

Full support Yes

Notes

Notes Chrome does not defer scripts with the defer attribute when the page is served as XHTML (application/xhtml+xml) - Chromium Issue #611136 , Chromium Issue #874749
Firefox Android Full support 4Opera Android Full support Yes

Notes

Full support Yes

Notes

Notes Opera does not defer scripts with the defer attribute when the page is served as XHTML (application/xhtml+xml) - Chromium Issue #611136 , Chromium Issue #874749
Safari iOS Full support YesSamsung Internet Android Full support Yes

Notes

Full support Yes

Notes

Notes Samsung Internet does not defer scripts with the defer attribute when the page is served as XHTML (application/xhtml+xml) - Chromium Issue #611136 , Chromium Issue #874749
Chrome Full support 45Edge Partial support 17Firefox Full support 43IE No support NoOpera Full support YesSafari Full support YesWebView Android Full support 45Chrome Android Full support 45Firefox Android Full support 43Opera Android?Safari iOS No support NoSamsung Internet Android Full support 5.0
Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support YesOpera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesFirefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support Yes
Chrome Full support 61Edge Full support 16Firefox Full support 60 Full support 60 No support 55 - 60

Disabled

Disabled
IE No support NoOpera Full support 48Safari Full support 11Firefox Android Full support 60 Full support 60 No support 55 - 60

Disabled

Disabled From version 55 until version 60 (exclusive): this feature is behind the dom.moduleScripts.enabled preference (needs to be set to true). To change preferences in Firefox, visit about:config.
Safari iOS Full support 11
Chrome Full support 70Edge Full support ≤79Firefox Full support 65IE No support NoOpera Full support YesSafari No support NoWebView Android Full support 70Chrome Android Full support 70Firefox Android Full support 65Opera Android?Safari iOS No support NoSamsung Internet Android Full support 10.0
Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support YesOpera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesFirefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support Yes
Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support YesOpera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesFirefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support Yes
Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support YesOpera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesFirefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support Yes
Chrome Full support 61Edge Full support 16Firefox Full support 60 Full support 60 No support 54 - 60

Disabled

Disabled
IE No support NoOpera Full support 48Safari Full support 10.1WebView Android Full support 61Chrome Android Full support 61Firefox Android Full support 60 Full support 60 No support 54 - 60

Disabled

Disabled From version 54 until version 60 (exclusive): this feature is behind the dom.moduleScripts.enabled preference (needs to be set to true). To change preferences in Firefox, visit about:config.
Opera Android Full support 45Safari iOS Full support 10.3Samsung Internet Android Full support 8.0
Chrome No support NoEdge No support NoFirefox No support? - 59IE No support NoOpera No support NoSafari No support NoWebView Android No support NoChrome Android No support NoFirefox Android No support? - 59Opera Android No support NoSafari iOS No support NoSamsung Internet Android No support No
Legend Full support Full support Partial support Partial support No support No support Compatibility unknown Compatibility unknown Experimental. Expect behavior to change in the future. Experimental. Expect behavior to change in the future. Non-standard. Expect poor cross-browser support. Non-standard. Expect poor cross-browser support. Deprecated. Not for use in new websites. Deprecated. Not for use in new websites. See implementation notes. See implementation notes. User must explicitly enable this feature. Compatibility notes

In older browsers that don"t support the async attribute, parser-inserted scripts block the parser; script-inserted scripts execute asynchronously in IE and WebKit, but synchronously in Opera and pre-4 Firefox. In Firefox 4, the async DOM property defaults to true for script-created scripts, so the default behavior matches the behavior of IE and WebKit.

To request script-inserted external scripts be executed in the insertion order in browsers where the document.createElement("script").async evaluates to true (such as Firefox 4), set async="false" on the scripts you want to maintain order.

Never call document.write() from an async script. In Firefox 3.6, calling document.write() has an unpredictable effect. In Firefox 4, calling document.write() from an async script has no effect (other than printing a warning to the error console).

Async and Defer - JavaScript loading strategies


JavaScript is an integral part of any modern web application, and the strategies we decide to use for loading directly affect the performance of that very application. In this article, we'll try to understand the important differences between each approach, the pros and cons along with the performance implications and how to optimize for page interaction and load time.

To demonstrate, I will create a website consisting of the following external dependencies. Pay special attention to the appropriate file sizes, as file download times are directly proportional to this.

  • HTML - page ~ 1 MB. Contains the actual markup/content to show some dynamic output from JavaScript.
  • Image - image1.png ~ 5 MB
  • JavaScript - file1.JS ~3MB is the core (main file) of javascript and depends on HTML parsing. It is needed to show some dynamic content or mount a react/angular component on the page.
  • JavaScript - file2.js ~460B is a small, independent javascript file that interacts with the dom.
  • JavaScript - file3.js ~ 1.5 MB - This is a secondary js file and depends on file1.js to execute some lower priority code. This code is not immediately required for page rendering and user interaction; it shows icons social networks, comments, online help, launching some analytics tasks, etc.
Now it's time to analyze the different approaches

Approach-1 [scripts in head section]

In the first case, we will load all the scripts tags into the head section of our HTML. Below is a screenshot of the network analysis chrome tabs pages ready for user interaction.

Pros:

The code execution sequence of the various JS files will be preserved in the order in which the files were included in the HTML. In the current example, even if file2 and file3 were loaded before file1, the execution order will be correct.

Minuses:

In this scenario, HTML parsing will be paused until all 3 scripts in the head section have been loaded, parsed, and executed. Empty White screen will be shown to the user even if the HTML file has already been downloaded [but not parsed]. This is certainly not good for usability.

None of the above scripts will be able to access/manipulate the HTML page since the DOM is not ready yet. One of possible solutions The way to handle this problem is to listen for the DOMContentLoaded event and then execute the code after that. The DOMContentLoaded event is fired when the source HTML document has been fully loaded and parsed, without waiting for stylesheets, images to finish loading.

Approach-2 [scripts at the end]

To overcome the 2 problems we face in the first approach, let's load all 3 scripts at the bottom of the body tag.

Pros: HTML is parsed before scripts are loaded, so the user will be able to see the actual content right away instead of waiting for scripts.

Since all scripts are executed after HTML parsing, they can all access the DOM for any manipulation. The sequence of script execution is preserved.

Minuses:

There is no performance gain as such.

Approach-3 [Using Async attribute]

HTML5 introduced the async script attribute, which helps in loading relevant script files in parallel on another thread without affecting HTML parsing.

However, the corresponding script will be parsed and executed as soon as it finishes loading, regardless of whether HTML parsing is complete or not, and will have a reference to the DOM element up to that specific point.

Here you can clearly see that file2.js has been loaded before HTML file. However, while the browser is loading file2, it has not paused parsing the HTML and because of this, by the time it executes - it has a link to the html placeholder to introduce dynamic content.

Pros: Since the scripts are loaded on a different thread, HTML parsing will not be paused and the user will be able to see the immediate content instead of a white blank screen. The main performance gain, i.e. DOMContentLoaded time decreased from 47.68 seconds to only 21.12 seconds and is ~55% increase.

Minuses:

JS execution sequence is not preserved. It runs in the appropriate loading order, rather than the included sequence of scripts within the HTML. Browser support - Not supported on older web browsers i.e. IE 9 and below.

What happens if the JS is loaded before the DOM element is accessible? An error will be thrown.

Note: Placing scripts with the async attribute at the bottom of the body section will be useless and equivalent to approach-2.

Approach-4 [Using Defer attribute]

The Defer attribute will force the script to be executed only after HTML parsing has been completed. One very important point to consider here is that Chrome does not yet support deferring and has no effect on the duration of DOMContentLoaded. However, it executes scripts at the end of the HTML parsing.

Pros:

The script import sequence is maintained. So file3.js is only executed after file1 has finished loading and executed, even if file3 was loaded previously.

Browser support - It has better browser support compared to the async attribute, i.e. it is partially supported in IE v6-9

Scripts can access the DOM because it is only executed after the full HTML has been parsed.

Minuses:

Initially I thought there would be a delay best choice than async, but later discovered that Chrome doesn't support it yet [version 71.0.3578.98] and has no effect on the duration of DOMContentLoaded.

However, it works as expected in Firefox with a significant performance improvement.

conclusions

It is preferable to place script tags in the head section with the async attribute for third party libraries that depend on Google Analytics, Google reCAPTCHA or anything else that doesn't require DOM access because the corresponding scripts are loaded in parallel but executed immediately.

Use defer for all other scripts loaded in the head section as they will also be loaded in parallel but will only be executed once the HTML parsing is complete and the DOM is ready to be accessed/manipulated.

You can also use the DOMContentLoaded listener combination inside asynchronous scripts to perform the functionality later. Please leave your opinions and conclusions in the comments and I will be happy to discuss them with you.


The author of this material is I, Yuri Pakholkov. I provide services for writing programs in Java, C++, C# (and also consulting on them) and creating websites. I work with sites on CMS OpenCart, WordPress, ModX and self-written ones. In addition, I work directly with JavaScript, PHP, CSS, HTML - that is, I can improve your website or help with web programming.

Greetings, friends! Did you know that JavaScript loading is one of the biggest bottlenecks in website performance? Today my main task is to explain what a script is and how it affects the speed and performance of the site.

A browser that loads a script tag stops rendering the page until the script has loaded and executed. The page is blocked and the browser does not respond to user actions for a couple of seconds. The delay time depends on several factors:

  • configurations,
  • Internet connection speed,
  • file size and others...

For this reason, the Google PageSpeed ​​Insights website speed analyzer recommends removing rendering-blocking JavaScript code at the top of the page. A good practice is to place scripts at the bottom of the site, for example before the closing tag or set up asynchronous loading.

If the script code affects the display of the top part of the site, do not put it in a separate file, but embed it directly into the HTML.

JS can change the site's content and even redirect to a different URL. In this case, connecting the script at the end of the document will lead to the effect of “twitching” the page, loading new or changing existing elements at the top.

Applying the async and defer attributes to the script tag

Let's figure out what asynchronous and deferred work in JavaScript is and what the fundamental difference is between the async and defer attributes. But first, let's look at the sequence of processing a document with the usual inclusion of a script tag.

< src ="example.js" >

For a visual example I will use the following symbols:

— page processing
— script loading
— script execution

Thus, the processing sequence occurs according to the following scheme:

Parsing the HTML code is interrupted while the script is loading and executing, after which it continues. There is a delay in displaying the web page.

defer attribute

The defer attribute allows the browser to start downloading js files in parallel without stopping further processing of the page. They are executed after full analysis object model document (from the English Document Object Model, abbreviated DOM), while the browser guarantees consistency based on the order in which the files are connected.

< defer src ="example.js" >async attribute

Support for the async attribute appeared in HTML5, it allows the browser to download js files in parallel and execute them immediately after downloading, without waiting for the rest of the page to be processed.

< async src ="example.js" >

Processing sequence diagram:

This is an asynchronous download. This attribute is recommended for use in scripts that do not have a significant impact on the display of the document. These include statistics collection counters (Google Analytics, Yandex Metrica), advertising network codes (Yandex Advertising Network, Google AdSense), social network buttons, and so on.

Website loading speed is one of the ranking factors in Google.

Asynchronous JavaScript connectivity reduces page load times by eliminating latency. Along with this, I recommend compressing and merging js files into one, for example, using the . Users like fast sites 😎

Plug-in scripts (JavaScript) blocks loading of HTML code. When the browser (parser) reaches the tag, it stops to load the content of the file and execute its code, and only then continues parsing the HTML.

This behavior can slow down HTML rendering when there are many JavaScript files loaded on a page. Often the code of these files is not needed to show HTML pages. This is why it is recommended to include scripts at the end of the page. However, this recommendation cannot always be followed and in such cases there are other ways to avoid blocking HTML rendering.

The element has two attributes, async and defer, which can give us more control over how and when the file is downloaded and executed.

Normal execution ... ... .... async attribute
defer attribute
Where and what to use?

Depends on the situation. Let's consider several questions on this topic.

Where is the element located?

If JavaScript file is located immediately before the closing tag, it makes no sense to use async or defer since by this moment the parser has already analyzed all the HTML code.

Is the script self-contained?

For files (scripts) that are not needed for other scripts to work and do not themselves have dependencies on other scripts, the async attribute is especially useful. Since in this case it does not matter at what point the script is executed, asynchronous loading is the most suitable option.

Do I need a fully loaded DOM for the script to work?

If this is necessary, then using async is appropriate only if the script is designed for asynchronous loading - i.e. it waits for the event until the DOM is loaded and only then starts its work.

Or you can use the defer attribute. In this case, you can place the script call anywhere in the HTML.

Is the script small?

If the script is relatively small and depends on it or it depends on other scripts, then it can be embedded directly in the HTML (connect inline).

Browser support 97% Adding defer or async attributes in WordPress

There are no standard ways to do this, so we will use the script_loader_tag hook:

Add_action("wp_enqueue_scripts", "my_scripts_method"); function my_scripts_method())( // connect the script wp_enqueue_script("my-script", get_template_directory_uri() . "/js/my-script.js"); // Add the defer attribute to the script with id `my-script` add_filter(" script_loader_tag", "change_my_script", 10, 3); function change_my_script($tag, $handle, $src)( if("my-script" === $handle)( // return str_replace(" src", " async src", $tag); return str_replace(" src", " defer src", $tag); ) return $tag; ) )

Synchronous scripts are bad, they force the browser to block the construction of the DOM tree: first you need to receive the script, execute it, and only then continue processing the rest of the page. This is of course nothing new to you, and the reason why we as evangelists have been promoting the use of asynchronous scripting. Here's a simple example:

var script = document .createElement("script" );

script.src = "http://somehost.com/awesome-widget.js" ;

document .getElementsByTagName("head" ).appendChild(script);

What is the difference? In the “bad” version, we block the construction of the DOM tree, wait until the script is loaded and executed, and only then continue processing the rest of the document. In the second example, we immediately start executing a script that creates a script element pointing to an external resource, add it to the document, and continue processing the DOM. The difference is subtle, but very important: dynamically created scripts are not blocking. So, that's great, right? Dynamically created scripts are a thing! Not so fast. Inline JavaScript has a small but important (and often overlooked) pitfall: CSSOM blocks it before execution. Why? The browser does not know what exactly such a script plans to do, and since JavaScript can manipulate

CSS properties

, it blocks and waits while the CSS is parsed and the CSSOM is built. It is better to see once than to hear a hundred times, consider the following example:

Wait a second, what's going on? Both scripts will be preloaded and executed ~2.7 seconds after the page loads.

Note that the scripts will still only be executed after the CSS is available (~2.7 seconds), but since the scripts are already loaded when the CSSOM becomes available, we can execute them immediately, saving over a second of processing time. Did we do everything wrong?

Before we answer that question, let's look at another example, this time with the "async" attribute:

If the async attribute is present, the script will be executed asynchronously as soon as it is available. If the attribute is missing, ... then the script is loaded and executed immediately, before further parsing of the document continues.