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.
Content categories |
Permitted content |
Tag omission |
Permitted parents |
Permitted ARIA roles |
DOM interface |
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
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 |
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 Internet | |||||||||||
Chrome Full support 1 | Edge Full support 12 | Firefox Full support 1 Notes Full support 1Notes 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 Yes | Opera Full support Yes | Safari Full support Yes | ||||||
Chrome Full support 1 | Edge Full support 12 | Firefox Full support 1 | IE Full support Yes | Opera Full support Yes | Safari Full support Yes | WebView Android Full support Yes | Chrome Android Full support Yes | Firefox Android Full support 4 | Opera Android Full support Yes | Safari iOS Full support Yes | Samsung Internet Android Full support Yes |
Chrome Full support 30 | Edge Full support ≤18 | Firefox Full support 13 | IE No support No | Opera Full support 12 | Safari Full support Yes Notes Full support YesNotes Notes The crossorigin attribute was implemented in WebKit in WebKit bug 81438. | WebView Android Full support Yes | Chrome Android Full support Yes | Firefox Android Full support 14 | Opera Android? | Safari iOS? | Samsung Internet Android Full support Yes |
Chrome Full support Yes Notes Full support YesNotes Notes Chromium Issue #611136, Chromium Issue #874749 | Edge Full support 12 | Firefox Full support 3.5 Notes Full support 3.5Notes 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 10Notes 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 YesNotes Notes Chromium Issue #611136, Chromium Issue #874749 | Safari Full support Yes | WebView Android Full support Yes Notes Full support YesNotes 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 YesNotes 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 4 | Opera Android Full support Yes Notes Full support YesNotes 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 Yes | Samsung Internet Android Full support Yes Notes Full support YesNotes 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 45 | Edge Partial support 17 | Firefox Full support 43 | IE No support No | Opera Full support Yes | Safari Full support Yes | WebView Android Full support 45 | Chrome Android Full support 45 | Firefox Android Full support 43 | Opera Android? | Safari iOS No support No | Samsung Internet Android Full support 5.0 |
Chrome Full support 1 | Edge Full support 12 | Firefox Full support 1 | IE Full support Yes | Opera Full support Yes | Safari Full support Yes | WebView Android Full support Yes | Chrome Android Full support Yes | Firefox Android Full support 4 | Opera Android Full support Yes | Safari iOS Full support Yes | Samsung Internet Android Full support Yes |
Chrome Full support 61 | Edge Full support 16 | Firefox Full support 60 Full support 60 No support 55 - 60 Disabled Disabled | IE No support No | Opera Full support 48 | Safari Full support 11 | Firefox 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 70 | Edge Full support ≤79 | Firefox Full support 65 | IE No support No | Opera Full support Yes | Safari No support No | WebView Android Full support 70 | Chrome Android Full support 70 | Firefox Android Full support 65 | Opera Android? | Safari iOS No support No | Samsung Internet Android Full support 10.0 |
Chrome Full support 1 | Edge Full support 12 | Firefox Full support 1 | IE Full support Yes | Opera Full support Yes | Safari Full support Yes | WebView Android Full support Yes | Chrome Android Full support Yes | Firefox Android Full support 4 | Opera Android Full support Yes | Safari iOS Full support Yes | Samsung Internet Android Full support Yes |
Chrome Full support 1 | Edge Full support 12 | Firefox Full support 1 | IE Full support Yes | Opera Full support Yes | Safari Full support Yes | WebView Android Full support Yes | Chrome Android Full support Yes | Firefox Android Full support 4 | Opera Android Full support Yes | Safari iOS Full support Yes | Samsung Internet Android Full support Yes |
Chrome Full support 1 | Edge Full support 12 | Firefox Full support 1 | IE Full support Yes | Opera Full support Yes | Safari Full support Yes | WebView Android Full support Yes | Chrome Android Full support Yes | Firefox Android Full support 4 | Opera Android Full support Yes | Safari iOS Full support Yes | Samsung Internet Android Full support Yes |
Chrome Full support 61 | Edge Full support 16 | Firefox Full support 60 Full support 60 No support 54 - 60 Disabled Disabled | IE No support No | Opera Full support 48 | Safari Full support 10.1 | WebView Android Full support 61 | Chrome Android Full support 61 | Firefox 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 45 | Safari iOS Full support 10.3 | Samsung Internet Android Full support 8.0 |
Chrome No support No | Edge No support No | Firefox No support? - 59 | IE No support No | Opera No support No | Safari No support No | WebView Android No support No | Chrome Android No support No | Firefox Android No support? - 59 | Opera Android No support No | Safari iOS No support No | Samsung Internet Android No support No |
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.
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 tagLet'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 attributeThe 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 attributeSupport 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![](https://i2.wp.com/wp-kama.ru/wp-content/uploads/2019/05/Async-Execution.png)
![](https://i1.wp.com/wp-kama.ru/wp-content/uploads/2019/05/Defer-Execution.png)
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 WordPressThere 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.