Defer Attribute (Chrome)
Asked Answered
G

3

31

Chrome for me has always been a reference on web standards, unfortunately the defer isn't supported and IE supports it since version 5.5. Why ?

js.js

document.getElementById ("hi").innerHTML = "Hi :)";

HTML

<!DOCTYPE html>
<html>
    <head>
        <meta charset = "utf-8">
        <script defer="defer" src="js.js"></script>
        <title>Hi</title>
    </head>
    <body>
        <div id="hi"></div>
    </body>
</html>
Gamelan answered 17/10, 2010 at 4:16 Comment(4)
While I can't tell you why chrome doesn't use it, I believe you can use the "async" attribute to produce a similar effect (correct me if I'm wrong...)Lynnelynnea
Or you can just put the styles at the top of the page and the scripts at the bottom, like you're supposed to.Magnesium
@ChristianMann do you mean at the bottom of the page? Why would you do that? that's invalid markupReinold
You can put a script tag anywhere you want (inside of head or body). The current best-practice advice is to place all scripts just before the closing </body> tag.Magnesium
G
107

What do defer and async mean?

By default, a <script src=...></script> tag is evil! The browser must halt parsing the HTML until the script is downloaded and executed (since the script might call document.write(...) or define global variables that later scripts depend on). This means that any images and stylesheets that are after the script tag don't start downloading until after the script has finished downloading and executing. External scripts typically make the Web load much more slowly, which is why NoScript has become so popular.

Microsoft introduced defer to solve the problem. If you use <script defer src=...></script>, you promise not to call document.write(...). A defer external script will start downloading immediately but won't execute until after the page is rendered. After the page has rendered, all defer scripts are executed in the same order that they were declared. Not all browsers implement defer yet.

HTML5 introduced the async attribute which may execute any time--possibly before the page has finished parsing or even before other defer/async scripts that are still downloading. But it's harder to use multiple async scripts because their execution order is not guaranteed. Like defer, not all browsers implement async yet.

After all defer and async scripts have executed, the DOMContentLoaded and load events fire.

A brief history of defer and async

  • 1997 IE 4 introduces defer.
  • 1998 HTML 4 spec mentions defer, but unfortunately it doesn't say exactly when defer scripts execute (All in order? Before onload?). Thus, no other browsers implement defer because no one wants to reverse-engineer IE's behavior or break scripts that might depend on IE's peculiarities. (See the Mozilla feature request, for example).
  • 2006 HTML5 draft finally describes the details needed to implement defer: defer scripts should all be executed in order after the rest of the page is parsed, and before onload. It also introduces async to specify scripts that can execute whenever they are downloaded without having to wait for each other. Unfortunately, HTML5 contradicts IE by not allowing inline defer scripts. This breaks the invariant that all defer scripts are executed in order (if some defer scripts have src and some have inline content).
  • 2009 Gecko 1.9.1 (Firefox 3.5) supports defer.
  • 2010-01 Gecko 1.9.2 (Firefox 3.6) supports async.
  • 2010-09 defer and async are checked into Webkit. You should see it in Chrome and Safari very soon (it's already in the Chrome dev channel but it's a bit buggy).
  • We're still waiting for Opera to implement defer and async and for IE to implement async.

So what should a web developer use?

There's no single rule to follow at this time. You have to choose the solution that best balances simplicity, page render latency, and script execution latency for the set of browsers that access your website.

  • The simplest way to have the page render before the scripts execute, as others have pointed out, is to put your scripts at the bottom of the page. But if the scripts are essential, or the webpage contains lots of HTML, then you should put your scripts higher up on the page.
  • If your script is standalone and your customers use IE or new versions of Firefox, use <script async defer src=...></script>: This allows rendering to continue in parallel to script downloading for IE and the newest HTML5 browsers but causes pre-HTML5 browsers (including all versions of Opera) to block.
  • If one external script depends on another, mark them both defer (but not async) and they will be executed in the order that they were declared (except IE<=9 in certain conditions can execute them out of order). Again, this allows rendering to continue in parallel to script downloading in IE and HTML5-aware Gecko/Webkit, but older browsers and Opera will suffer. It's a good idea to use defer even if the scripts are at the bottom of the page so that they download in parallel with each other.
  • Never use defer for inline scripts because the HTML5 draft has taken away the execution order guarantee.
  • If your audience includes many Opera or old Firefox/Safari users, the following snippet will execute the script after parsing the document on most pre-HTML5 browsers (IE, Webkit, need to test old Firefox), while the newest HTML5-aware browsers start downloading immediately but won't block to execute the script because of the async attribute. In other words, most older browsers treat it like a script at the bottom of the page, and newest browsers recognize the async. But Opera users get the worst of both worlds, because Opera begins execution immediately and doesn't understand async. This is the pattern recommended by Google Analytics for the urchin on many webpages.

snippet:

<script>
(function() {
  var script = document.createElement('script');
  script.src = '...';
  script.async = true;
  var s = document.getElementsByTagName('script')[0];
  s.parentNode.insertBefore(script, s);
})();
</script>
  • If another script depends on the first script to load, then you can use the same pattern as above, but listen to the onload event of the first script element before executing the second script. See the LABjs example for how to wait for another script to load.
  • If you have multiple scripts with complicated dependencies, use LAB.js or the YUI Loader to make them download in parallel and execute in some valid order.
  • If you're using a popular library such as jQuery, consider using Google's copy rather than your own to increase the likelihood that the browser has already cached it.

Update: If you have scripts split into modules and want to improve performance, I recommend the "Coupling Asynchronous Scripts" chapter of Even Faster Web Sites by Steve Souder. It contains tips/tricks for not only controlling execution order but also to delay parsing of scripts to improve performance.

Gast answered 20/10, 2010 at 21:48 Comment(2)
I took this from here: "It's a good idea to use defer even if the scripts are at the bottom of the page so that they download in parallel with each other." Important one.Knew
Watch out for this issue: github.com/h5bp/lazyweb-requests/issues/42 TL;DR, defer does not guarantee order in IE <= 9 due to a bug, so "if one external script depends on another" and you use defer, you might still have problems.Benignant
I
1

defer is supported only by internet explorer. you don't need to rely on it. there are other ways to get the same effect, like placing your scripts at the end of the page just before the </body> tag, as others have pointed out.

The purpose of defer is to tell the externally linked script to wait until the page finishes loading until it runs. The same thing can be accomplished via good unobtrusive JavaScript methods, which usually include code that prevents scripts from executing until the DOM is finished loading.

The advantage of defer occurs in connection with Internet Explorer, since that browser is the only one that supports the defer attribute. So, if you need a quick script to run only in IE, and you don’t mind if the entire page loads before it starts to execute, then simply add defer="defer" in your tag and that will quickly take care of that problem. Fixing a transparent PNG issue in IE6 is one possible practical use for defer.

The defer attribute must be used when hiding a script from other browsers with a conditional comment that targets an IE-only script — otherwise the script will run normally in other browsers.)

Reference: http://www.impressivewebs.com/10-javascript-quick-tips-and-best-practices/

Idolize answered 17/10, 2010 at 4:52 Comment(1)
just a sidenote: defer is also supported in firefox 3.5+Toscana
U
0

If scripts can be deferred, they can also be moved to the bottom of the page (as pointed out by @Christian in the comments)

This would be a better choice in terms of performance, as it will not block the rest of the page from loading. You can place your scripts before the </body> tag.

This attribute is poorly supported by major browsers, this in itself should be a hint to stop using it.

Understudy answered 17/10, 2010 at 4:49 Comment(1)
The script element should never be stored within the body element...not unless you want to make the minimal effort and instead of working on the next cool thing spend all of your time on maintaining poor code instead.Wilson

© 2022 - 2024 — McMap. All rights reserved.