Javascript Load Order with Defer Attribute

HTML rendering and Javascript are sometimes mystery to me, and usually I can only understand how something works by experimenting. The implementation differs quite a bit between MSIE, Mozilla, Netscape 4 and other commonly used browsers as well, and it can be quite frustrating sometimes. And when the outcome of a script differs from its specification, it then really annoys me.

I was playing with some Javascript loading order test this morning, and here’s a simple page that I used for the test.


  
  
    
      
    
    
      
      
      
      

Javascript Test.

The order of alter() triggered is:

  • Head
  • Body 1
  • Body 2
  • Body 3
  • On load

Well. There is nothing surprising, except for “Body 2″ that is executed and triggered between “Body 1″ and “Body 3″, even though defer="true" attribute has been set. According to some Javascript FAQ and W3C’s own HTML 4 reference, defer="true" attribute is designed to execute scripts asynchronously, i.e. after the document has been parsed. Therefore I was expecting “Body 2″ to be displayed in between “Body 3″ and “On load”, or even after “On load” as it might be appended to the end of the message queue. But obviously the experiment says it is not, and I think I might need to go back fixing some of my other scripts as I always assume so. I guess according to the reference, defer="true" only provides as a hint that it is not going to affect the document structure, but the browser implementation does not need to accept the hint.

By the way, it is tested on both MSIE 6SP1 and Mozilla 1.4, and in the case of MSIE, the alert dialog box of “Body 2″ is actually around 50 pixels lower and further to the right, comparing with other alerts triggered. On Mozilla 1.4, there is no difference.

Updated at 11:58am: The example above does generate a different result if the deferred Javascript is fetched from else where…

Here is some changes to the HTML document:


      
      
      

Instead of doing an alert() to print out “Body 2″, it loads an external Javascript file named “test.js”. And the content of that file is simply…


  alert("Body 2");

Now, Mozilla 1.4 will continue to print out “Body 1″, “Body 2″ and “Body 3″ in order, but MSIE 6SP1 will honour the defer="true" attribute and print out “Body 1″, “Body 3″ and “Body 2″, and then finally “On Load”. If defer="true" attribute is not specified, then both Mozilla and MSIE will bring out the alerts in the order they are in the document.

I think MSIE’s behaviour is actually correct by asynchronously deferring operations that might be blocked on IO. I guess it makes more sense to Win32 developers as they are used to event driven networking programming. That also implies that MSIE might finish parsing the main document faster than Mozilla if there are a lot of external scripts linked over slow network. Obviously, parsing HTML document and displaying them involves much more than the network programming model, but here’s just a little thought on the implication.

Back to more coding…

Category: Uncategorized | Thu, 3 July 2003 10:44 am

Comments

1.
Avatar for Toby Inkster
Posted by Toby Inkster on Mon, 29 September 2003 9:07 pm

Mozilla might behave better if you were to use the more proper defer=”defer” rather than defer=”true”.


2.
Avatar for Peter Benoit
Posted by Peter Benoit on Wed, 19 November 2003 1:27 am

More proper? How do you figure? The defer attribute looks for a boolean; you know, yes/no, true/false, 1/0. You do understand that concept right?

Here’s some W3C for you, Mozilla boy.

defer [CI]
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.


3.
Avatar for Phil Frost
Posted by Phil Frost on Thu, 4 December 2003 11:00 am

actually, defer=”true” is quite wrong, as stated in the DTD and by the validator:

HTML 4.01 DTD:

<!ATTLIST SCRIPT
charset %Charset; #IMPLIED -- char encoding of linked resource --
type %ContentType; #REQUIRED -- content type of script language --
src %URI; #IMPLIED -- URI for an external script --
defer (defer) #IMPLIED -- UA may defer execution of script --
event CDATA #IMPLIED -- reserved for possible future use --
for %URI; #IMPLIED -- reserved for possible future use --
>

HTML validator output:

Line 15, column 48: value of attribute “DEFER” cannot be “TRUE”; must be one of “DEFER” (explain…).

<script type="text/javascript" defer="true">

That said, the HTML 4.01 standard does not explicitly state a behavior, and does not require the user agent to recognize the attribute:

“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.”

This is a poor specification, because an ambigious load order will cause problems if there are interdependencies between the script elements.


4.
Avatar for Hakan M
Posted by Hakan M on Thu, 15 January 2004 12:11 am

> More proper? How do you figure? The defer attribute
> looks for a boolean; you know, yes/no, true/false,
> 1/0. You do understand that concept right?

Great to see a complete idiot trying to talk smart and then find a correction right below it. The boolean operation is evaluated on the presence of a defer-attribute, meaning you can pretty much put anything as a value. It’s not evaluated by the string (“true”) in your value, since that is a STRING.

The fact that you use a value at all is that XHTML does not allow properties without values on elements, same thing with and so on.

YOU do understand the concept, right?


5.
Avatar for y2kprabu
Posted by y2kprabu on Sat, 9 April 2005 4:39 am

Great Discovery man…
i got to know that IE defers javascript only when the script is externaly linked
good work


6.
Avatar for no.connexion
Posted by no.connexion on Tue, 6 May 2008 2:59 am

Actually the correct procedure is defer=”defer” and mozilla based browsers will not accept this (and/or just ignore it) but in IE this JS attribute will execute the javascript INLINE or EXTERNAL only AFTER the page finisged loading.

Some links regarding this matter:
https://bugzilla.mozilla.org/show_bug.cgi?id=28293
http://www.hunlock.com/blogs/Deferred_Javascript


Add a comment

Gravatar is used. Email address is required but will not be displayed. Please keep your comment on topic. No spamming and/or bad language. First time poster will be moderated. Scott reserves the right to delete/edit your comments.