Evangelism/Firefox3.5/35Days/Articles/Defer on script elements: Difference between revisions

Jump to navigation Jump to search
Line 1: Line 1:
== '''WORK IN PROGRESS''' ==
== '''WORK IN PROGRESS''' ==


== defer  attribute for the  ‹script› element ==
== <tt>defer</tt> attribute for the <tt>&lt;script&gt;</tt>  element ==
 
In HTML, the <tt>script</tt> element allows authors to include dynamic script in their documents. The <tt>[http://www.w3.org/TR/html5/semantics.html#attr-script-defer defer]</tt> attribute is boolean attribute that indicate how the script should be executed. It was first introduced in Internet Explorer 4, and added in the [http://www.w3.org/TR/html401/interact/scripts.html#h-18.2.1 HTML 4 specification].<br>
If the <tt>defer</tt> attribute is present, then the script is executed when the page has finished parsing. The element must be added to the end of the list of scripts that will execute when the document has finished parsing. Think about a [http://en.wikipedia.org/wiki/FIFO_%28computing%29 FIFO] processing queue : the first script element to be added to the queue will be the first script to be executed, then processing proceeds sequentially in the same order.
 
==== First test ====
 
Here is a simple first test to see how the attribute works. The following lines are in the <tt>head</tt> element of a page :
 
&#139;script&#155;
var test1 = &#34;Test 1 : fail&#34;;
&#139;/script&#155;
&#139;script <font style="color: green;">defer</font>&#155;
  console.log(test1);
&#139;/script&#155;
&#139;script&#155;
test1 = &#34;Test 1 : pass&#34;;
&#139;/script&#155;
 
If the <tt>defer</tt> attribute for the <tt>script</tt> element is correctly implemented in the browser which renders the page, the second script element is executed after all the others, and the [https://addons.mozilla.org/en-US/firefox/addon/1843 Firebug] console should display <tt><font style="color: blue;">"Test 1 : pass"</font></tt>.<br> Otherwise, the console displays  <tt><font style="color: blue;">"Test 1 : fail"</font></tt> because the scripts are executed in the same order than in the source code.
 
The correct syntax for XHTML documents is
&lt;script <font style="color: green;">defer="defer"</font>&gt;&lt;/script&gt;
 
==== Second test ====
 
This second test is a way to see how the feature works in a webpage with multiples <tt>script</tt> elements inserted :
* inline in the <tt>head</tt> and <tt>body</tt> elements
* external via <tt>src</tt> attribute in <tt>head</tt> and <tt>body</tt> elements
* with dynamic DOM insertion
 
Here follow the partial source code of this webpage :
 
&#139;!doctype html&#155;
&#139;html&#155;
    &#139;head&#155;
        &#139;title&#155; Test 2 &#139;/title&#155;
        &#139;script&#155; var test2 = "Test 2 :\n\n"; &#139;/script&#155;
        &#139;script&#155; document.addEventListener("DOMContentLoaded",
                function(){
                        test2 += "\t<font style="color: red;">DOMContentLoaded</font>\n";
                }, false);
        &#139;/script&#155;
        &#139;script <font style="color: green;">defer</font>&#155; test2 += "\t<font style="color: red;">Inline HEAD deferred</font>\n"; &#139;/script&#155;
        &#139;script&#155; test2 += "\t<font style="color: red;">Inline HEAD</font>\n"; &#139;/script&#155;
        &#139;script src="script1.js" <font style="color: green;">defer</font>&#155;
                // <font style="color: red;">External HEAD deferred (script1.js)</font>
        &#139;/script&#155;
        &#139;script src="script2.js"&#155;
                // <font style="color: red;">External HEAD  (script2.js)</font>
        &#139;/script&#155;
&#139;script&#155;
            // <font style="color: red;">Dynamic DOM insertion of a script (script3.js)</font>
            head = document.getElementsByTagName('head')[0];
            script3 = document.createElement('script');
            script3.setAttribute('src', 'script3.js');
            head.appendChild(script3);
            // <font style="color: red;">Dynamic DOM insertion of a deferred script (script4.js)</font>
            script4 = document.createElement('script');
            script4.setAttribute('defer', '<font style="color: green;">defer</font>');
            script4.setAttribute('src', 'script4.js');
            head.appendChild(script4);
&#139;/script&#155;
&#139;script <font style="color: green;">defer</font>&#155;
            // <font style="color: red;">Deferred dynamic DOM insertion of a script (script5.js)</font>
            head = document.getElementsByTagName('head')[0];
            script5 = document.createElement('script');
            script5.setAttribute('src', 'script5.js');
            head.appendChild(script5);
            // <font style="color: red;">Deferred dynamic DOM insertion of a deferred script (script6.js)</font>
            script6 = document.createElement('script');
            script6.setAttribute('defer', '<font style="color: green;">defer</font>');
            script6.setAttribute('src', 'script6.js');
            head.appendChild(script6);
&#139;/script&#155;
    &#139;/head&#155;
    &#139;body onload="test2 += '\t<font style="color: red;">Body onLoad</font>\n';"&#155;
        &#139;script <font style="color: green;">defer</font>&#155; test2 += "\t<font style="color: red;">Inline BODY deferred</font>\n"; &#139;/script&#155;
        &#139;script&#155; test2 += "\t<font style="color: red;">Inline BODY</font>\n"; &#139;/script&#155;
... other body content ...
&lt;a onclick="alert(test2);"&gt;Launch test 2&lt;/a&gt;
   
... other body content ...
   
        &#139;script src="script7.js" <font style="color: green;">defer</font>&#155;
                // <font style="color: red;">External BODY deferred (script7.js)</font>
        &#139;/script&#155;
        &#139;script src="script8.js"&#155;
                // <font style="color: red;">External BODY (script8.js)</font>
        &#139;/script&#155;
    &#139;/body&#155;
&#139;/html&#155;
 
By clicking the link "Launch test 2", a pop-up appears with a list in it. This list shows the order of <tt>script</tt> elements loaded during the session.
 
The test displays also the <tt>DOMContentLoaded</tt> and <tt>body.onload</tt> events when they are fired.
 
If the <tt>defer</tt> attribute is correctly implemented in the browser, all the deferred lines should be near the bottom of the list.
 
Results of the second test for each browser are below (deferred scripts are in green color) :
 
* '''The <tt>defer</tt> attribute behavior in the Firefox 3.5 browser is correct''' :
*#Inline HEAD
*#External HEAD (script2.js)
*#Dynamic DOM insertion of a script (script3.js)
*#Inline BODY
*#External BODY (script8.js)
*#<font style="color: green;">Inline HEAD deferred</font>
*#<font style="color: green;">External HEAD deferred (script1.js)</font>
*#<font style="color: green;">Dynamic DOM insertion of a deferred script (script4.js)</font>
*#<font style="color: green;">Inline BODY deferred</font>
*#<font style="color: green;">External BODY deferred (script7.js)</font>
*#<font style="color: green;">Deferred dynamic DOM insertion of a script (script5.js)</font>
*#<font style="color: green;">Deferred dynamic DOM insertion of a deferred script (script6.js)</font>
*#DOMContentLoaded
*#Body onLoad
 
* '''The <tt>defer</tt> attribute behavior in the IE 8 browser is ''erratic'' : the order is different at each reload''' :
*#Inline HEAD
*#External HEAD (script2.js)
*#Inline BODY
*#External BODY (script8.js)
*#Dynamic DOM insertion of a script (script3.js)
*#<font style="color: green;">Dynamic DOM insertion of a deferred script (script4.js)</font>
*#<font style="color: green;">Inline HEAD deferred</font>
*#<font style="color: green;">External HEAD deferred (script1.js)</font>
*#<font style="color: green;">Inline BODY deferred</font>
*#<font style="color: green;">External BODY deferred (script7.js)</font>
*#Body onLoad
*#<font style="color: green;">Deferred dynamic DOM insertion of a script (script5.js)</font>
*#<font style="color: green;">Deferred dynamic DOM insertion of a deferred script (script6.js)</font>
 
* '''The <tt>defer</tt> attribute behavior in a WebKit browser (Safari 4.0) is ''erratic'' : the order is different at each reload''' :
*#<font style="color: green;">Inline HEAD deferred</font>
*#Inline HEAD
*#<font style="color: green;">External HEAD deferred (script1.js)</font>
*#External HEAD (script2.js)
*#<font style="color: green;">Inline BODY deferred</font>
*#Inline BODY
*#<font style="color: green;">External BODY deferred (script7.js)</font>
*#<font style="color: green;">Deferred dynamic DOM insertion of a script (script5.js)</font>
*#<font style="color: green;">Dynamic DOM insertion of a deferred script (script4.js)</font>
*#<font style="color: green;">Deferred dynamic DOM insertion of a deferred script (script6.js)</font>
*#Dynamic DOM insertion of a script (script3.js)
*#External BODY (script8.js)
*#DOMContentLoaded
*#Body onLoad
 
* '''The <tt>defer</tt> attribute behavior in the Opera 10.00 Beta browser''' :
*#<font style="color: green;">Inline HEAD deferred</font>
*#Inline HEAD
*#<font style="color: green;">External HEAD deferred (script1.js)</font>
*#External HEAD (script2.js)
*#Dynamic DOM insertion of a script (script3.js)
*#<font style="color: green;">Dynamic DOM insertion of a deferred script (script4.js)</font>
*#<font style="color: green;">Deferred dynamic DOM insertion of a script (script5.js)</font>
*#<font style="color: green;">Deferred dynamic DOM insertion of a deferred script (script6.js)</font>
*#<font style="color: green;">Inline BODY deferred</font>
*#Inline BODY
*#<font style="color: green;">External BODY deferred (script7.js)</font>
*#External BODY (script8.js)
*#DOMContentLoaded
*#Body onLoad
 
==== Conclusion ====
 
Currently, between the 4 recent browsers tested, Firefox 3.5 only supports the <tt>defer</tt> attribute correctly.
 
==== Further reading and inspiration ====
 
* The fixed bug 28293 - (defer) scripts with defer attribute not deferred : {{bug|28293}}
* The "JavaScript: Defer Execution" article on the WebsiteOptimization website : http://www.websiteoptimization.com/speed/tweak/defer/

Navigation menu