How Exactly Does ≪Script Defer="Defer"≫ Work

How exactly does script defer=defer work?

UPDATED: 2/19/2016

Consider this answer outdated. Refer to other answers on this post for information relevant to newer browser version.


Basically, defer tells the browser to wait "until it's ready" before executing the javascript in that script block. Usually this is after the DOM has finished loading and document.readyState == 4

The defer attribute is specific to internet explorer. In Internet Explorer 8, on Windows 7 the result I am seeing in your JS Fiddle test page is, 1 - 2 - 3.

The results may vary from browser to browser.

http://msdn.microsoft.com/en-us/library/ms533719(v=vs.85).aspx

Contrary to popular belief IE follows standards more often than people let on, in actuality the "defer" attribute is defined in the DOM Level 1 spec http://www.w3.org/TR/REC-DOM-Level-1/level-one-html.html

The W3C's definition of defer: http://www.w3.org/TR/REC-html40/interact/scripts.html#adef-defer:

"When set, this boolean attribute provides a hint to the user agent that the script is not going to generate any document content (e.g., no "document.write" in javascript) and thus, the user agent can continue parsing and rendering."

For what is defer=defer in js?

It causes the browser to defer parsing of the script (not necessarily delay loading).

Normally when the browser encounters a script tag, it pauses any further procesing of the HTML until the script has been downloaded, fetched, parsed (then compiled on most browsers) and executed. This is necessary to allow the javascript to inject html via document.write().

However this often means that the user is left looking at a blank screen for a long time.

With the defer tag, the script is not parsed/compiled until the HTML is fully loaded. If you have multiple script tags with the defer atrtribute, then the order in which they are parsed is maintained.

This is all extensively documented on the internet. The w3c pages are a good place to start (but can be a bit terse).

Script Tag - async & defer

Keep your scripts right before </body>. Async can be used with scripts located there in a few circumstances (see discussion below). Defer won't make much of a difference for scripts located there because the DOM parsing work has pretty much already been done anyway.

Here's an article that explains the difference between async and defer: http://peter.sh/experiments/asynchronous-and-deferred-javascript-execution-explained/.

Your HTML will display quicker in older browsers if you keep the scripts at the end of the body right before </body>. So, to preserve the load speed in older browsers, you don't want to put them anywhere else.

If your second script depends upon the first script (e.g. your second script uses the jQuery loaded in the first script), then you can't make them async without additional code to control execution order, but you can make them defer because defer scripts will still be executed in order, just not until after the document has been parsed. If you have that code and you don't need the scripts to run right away, you can make them async or defer.

You could put the scripts in the <head> tag and set them to defer and the loading of the scripts will be deferred until the DOM has been parsed and that will get fast page display in new browsers that support defer, but it won't help you at all in older browsers and it isn't really any faster than just putting the scripts right before </body> which works in all browsers. So, you can see why it's just best to put them right before </body>.

Async is more useful when you really don't care when the script loads and nothing else that is user dependent depends upon that script loading. The most often cited example for using async is an analytics script like Google Analytics that you don't want anything to wait for and it's not urgent to run soon and it stands alone so nothing else depends upon it.

Usually the jQuery library is not a good candidate for async because other scripts depend upon it and you want to install event handlers so your page can start responding to user events and you may need to run some jQuery-based initialization code to establish the initial state of the page. It can be used async, but other scripts will have to be coded to not execute until jQuery is loaded.

Script defer doesn't seem to work as expected

defer only works on external scripts:

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.

To achieve a similar effect for dynamically inserted scripts use async=false instead. Scripts with the defer attribute will execute in the order in which they appear in the document.

Also,

Scripts without async or defer attributes, as well as inline scripts, are fetched and executed immediately, before the browser continues to parse the page.

Because local scripts are executed before the page finishes parsing, defer will not apply. defer gets applied after parsing, but before DomContentLoaded.

wordpress script_loader_tag in function.php

Replace

$scripts_to_defer = array('jquery-core-js','fortuna.lib-js');

With this

$scripts_to_defer = array( 'jquery-core', 'fortuna.lib' );

You don't need to add -js to handle because WordPress automatically adds when enqueue scripts Try the below code.

function add_defer_attribute( $tag, $handle ) {
// add script handles to the array below
$scripts_to_defer = array( 'jquery-core','fortuna.lib' );
foreach( $scripts_to_defer as $defer_script ) {
if ($defer_script === $handle) {
return str_replace( ' src', ' defer="defer" src', $tag );
}
}
return $tag;
}
add_filter( 'script_loader_tag', 'add_defer_attribute', 10, 2 );

function add_async_attribute( $tag, $handle ) {
// add script handles to the array below
$scripts_to_async = array( 'jquery-core', 'fortuna.lib' );
foreach( $scripts_to_async as $async_script ) {
if ($async_script === $handle) {
return str_replace( ' src', ' async="async" src', $tag );
}
}
return $tag;
}
add_filter( 'script_loader_tag', 'add_async_attribute', 10, 2 );

Tested and working fine.

Sample Image

Can you use both the async and defer attributes on a HTML tag?

From the specification: https://www.w3.org/TR/2011/WD-html5-20110525/scripting-1.html#attr-script-async

The defer attribute may be specified even if the async attribute is specified, to cause legacy Web browsers that only support defer (and not async) to fall back to the defer behavior instead of the synchronous blocking behavior that is the default.

(Check the reference link below to see a visual representation of the differences between normal scripts and scripts with defer and async)


References:

  • async vs defer attributes
  • Efficiently load JavaScript with defer and async

document.createElement('script') vs script src=

The <script src=...> blocks the browser while document.createElement('script') loads the JavaScript asynchronously; this is the primary reason.


The <script src=...> tag blocks browser from displaying rest of the page until the script is loaded and executed. This ensures that scripts are executed in correct order and any document.write() in that script work as expected. However this creates a laggy browsing experience for the user.

When the script is loaded asynchronously, the browser can download the script without blocking the page display. This improves the browsing experience dramatically.

To load the scripts asynchronously one can use HTML markup:

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

The async attribute was introduced in HTML5 while the defer attribute can be added as a fallback for older versions of IE. This document describes how async and defer attribute work.

Alternately, one can use JavaScript to build a script tag:

var s = document.createElement('script');
s.src = "...";
document.getElementsByTagName("head")[0].appendChild(s);

JavaScript generated script tags work in most browsers even if they do not understand the async attribute or .async = true property.


About schemeless URIs (//example.com/script.js): schemeless URIs seem to work almost everywhere (see this question).

About the Google Analytics example: both old and new code use JavaScript to detect the protocol then load http://www. or https://ssl. which is not possible via HTML markup.



Related Topics



Leave a reply



Submit