Closed Bug 28293 Opened 24 years ago Closed 16 years ago

scripts with defer attribute not deferred

Categories

(Core :: DOM: Core & HTML, defect, P1)

defect

Tracking

()

VERIFIED FIXED

People

(Reporter: ian.graham, Assigned: sicking)

References

Details

(4 keywords, Whiteboard: [HTML4-18.2.1] [ie-parity] [See comment 26 & 80 for desired behavior])

Attachments

(7 files, 3 obsolete files)

From Bug Helper:
User-Agent: Mozilla/5.0 [en-CA] (Windows_98; I)
BuildID:    2000012520
The attribute defer="defer" should allow script element content
to be deferred execution until after the page is rendered. The example
URL demonstrates this using a simple alert() popup which blocks the
rendering of the subsequent page, even though the script block is
'deferred'.

Steps to Reproduce:

See example URL. If defer="defer" is supported, the text of the document should
be rendered _before_ you dismiss the alert() popup. If defer
is not supported, then you will need to dismiss the alert() before
the page is rendered.

Notes:

Defer was not supported in Nav 4, but is supported in IE 5.x, and I believe
IE 4. It is of mixed use, however, as it seems that not all script code can
be deferred.

I tagged this as normal, but it may in fact be better marked as an
enhancement, since it is not a blocker, and there are workarounds possible
by moving code to teh end of the document body.
clayton: what's your call on supporting this?
Assignee: rickg → clayton
I wanted to ask expert help from the user perspecive on this issue, so emailed 
andreww.  I asked if users will need this facility and if he had ever needed it 
in his former life doing JS programming in Professional Services.  Andrew 
replies:


Well, there are other ways to defer execution of scripting on load. 
I've never had a case where I said 'gee, I wish I could not run this 
until after the page loaded' since I just place the startup code to 
run on a body.onload handler.

But on the other hand, if it's in ECMAscript, it should be supported..
Id say there are bigger fish to fry...
-- 

A final observation, 'defer' is not part of the language standard.  And I assume 
it's not DOM.
= C =
Assignee: clayton → rickg
Actually, 'defer' has been part of the HTML standard since HTML 4.0
"strict" (see Section 18.2.1 of the HTML 4.01 spec).  The formal description
is:

  "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. "

I would thus not expect 'defer' to be described in the ECMA spec, since
this is processing environment (and not language) issue.  
However, I do agree with Andrew -- the methods he suggests for deferring
execution (body.onload handler, or my lazy favorite of just plopping the 
script at the end of the body element) can accomplish the same things, 
however inelegantly (in my example, not Andrew's) 

Indeed, could one not imagine that <script defer="defer" ...> is essentially 
equivalent to wrapping the script content in a function, and
then running this function from the body.onload handler?  If this is so,
then it _might_ be easy to implement.

Vidur -- is this part of the DOM spec? If so, the I think we may need to support 
it.
Assignee: rickg → vidur
Hmm -- trying to reassign to vidur so he can make the call.
The SCRIPT attribute "defer" is a hint and not a mandate to the user 
agent and should not be used in place of mechanisms such as the one 
Andrew suggested. Special processing of SCRIPT elements with "defer" set is an 
RFE that I am currently inclined to mark LATER given the volume of bugs that we 
currently have.
Status: NEW → RESOLVED
Closed: 24 years ago
Resolution: --- → LATER
Summary: defer attribute not supported on script elements → RFE: defer attribute not supported on script elements
Keywords: verifyme
massive update for QA contact.
QA Contact: petersen → lorca
Being that no one has complained in over 7 months, I'll verify this as LATER.
Status: RESOLVED → VERIFIED
*** Bug 93392 has been marked as a duplicate of this bug. ***
This bug blocks bug 7954, bug 41368.  Technically, this is an enhancement but
leaving as normal since it is HTML standard and should be fixed.  Adding HTML4
keyword.  Should we re-open this for re-evaluation?
Blocks: html4.01, robin's
Keywords: verifymehtml4
LATER is deprecated. Setting Target Milestone to "Future" instead.
Status: VERIFIED → REOPENED
Resolution: LATER → ---
Target Milestone: --- → Future
SPAM. HTML Element component deprecated, changing component to Layout. See bug
88132 for details.
Component: HTML Element → Layout
OS: Windows 98 → All
Hardware: PC → All
QA Contact: bugzilla → gerardok
From the HTML 4.01 spec: "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." 
QA Contact: gerardok → moied
Whiteboard: [HTML4-18.2.1]
Keywords: perf
so I'm reading this bug... and everyone is assuming that "defer" means "execute
once all the content is rendered".  I see nothing to support that
interpretation.  To me, it says "this script has nothing to do with content
rendering and they can be done in any order".  In particular, there is no reason
not to render while the script is coming in, execute it once it comes in off the
network, then continue rendering.  Or am I missing something?
The DTD for the "defer" attribute also has the comment "UA may defer execution of script". Support is optional.

It might be desirable to implement deferred execution to improve rendering speed on pages with many JavaScript functions in a <script defer>. However, I agree with Christopher; this should have severity set to "enhancement".

In any case, changing misleading summary to "scripts with defer attribute not deferred".
Summary: RFE: defer attribute not supported on script elements → RFE: scripts with defer attribute not deferred
So how does IE implement this?  In particular:

1)  <script src="foo" defer>
    <script src="bar">

   Can the second script access things defined in the first one?

2)  <script src="foo" defer>
    <script src="bar" defer>

   Is the second script guaranteed to load after the first one?  (in IE; I
   realize that the HTML spec says absolutely nothing here)
Microsoft's documentation of the "defer" attribute (http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/defer.asp) makes no guarantees.

The following produces no output with IE6 under WinXP:

<script defer>
var test = "<p>This is a test.<\/p>";
</script>
<script>
document.write(test);
</script>
That produces no output or that throws a "test is not defined" error?
Also, it does not matter what the documentation says; what matters is what the
actual behavior is.... :(
No output and a "'test' is undefined" error popup, if script error notification is turned on.
Hi,

The defer attribute can be an extremely performance enhancing feature, to the
extent where in relevant cases Mozilla at present performs  very slow compared
with IE.

Consider this HTML code:

<SCRIPT>
function init(){
}// function
</SCRIPT>
<SCRIPT src=someurl.js defer>
<SCRIPT>
document.write('<FRAMESET rows="50%,50%" onLoad=init()>');
    document.write('<FRAME src="some_otherurl_1">');
    document.write('<FRAME src="some_otherurl_2">');
document.write('</FRAMESET>);
</SCRIPT>

The above works beautifully in IE but turns out to be very ugly with Mozilla.

The deferred script holds up the writing of the frameset until it is actually 1)
loaded over the network, 2) compiled and 3) initialised.
This creates a bad performance degradation. The page literally hangs for quite a
while. Please consider that framesets by themselves already have a built-in
disadvantage.
I would tend to give this a higher priority and some milestone because I think
it is a commonly used feature that makes Mozilla look ugly in comparison with IE.
> I think it is a commonly used feature

Can you back that up with hard numbers?  Preferably on top100 or top500 sites? 
That would really make it easier to convince people to prioritize this bug more
highly, you know...

This bug still needs an answer to question #2 in comment 16 (many thanks to
Robin for answering question #1).
Sorry, I can't provide any info about other sites. My guess was derived from
news post frequencey and the fact that IE4 already supports this.

And the pseudo testcase should serve as a good basis for discussion.

I am normally embedding scripts so this is not a great issue for myself - just
had a case where IE's stunning performance highlighted the potential of this trick.

Re question 2) I would not rely on any sequence even if a test would prove my
trivial guess that they are executed in the order they are written.

Of course I would prefer it this way because otherwise programming might get
very tricky in such cases.
Attached file Testcase for this bug... (obsolete) —
Attached file Real testcase for this bug (obsolete) —
Attachment #90759 - Attachment is obsolete: true
Since some people seem to not understand the concept explained in comment #19....

I finally got my hands on IE6/Windows and tested with the attached testcase. 
The behavior seems to be as follows:

1)  First load any non-defer scripts
2)  Then load inline defer scripts
3)  Then load external defer scripts

with each set of loads happening in document order.  Any corrections to this
analysis would be most welcome (timeouts of arbitrary length between 1 and 99
seconds can be gotten by changing the source in the obvious way).

I cannot for the life of me figure out why #2 and #3 are separate groups of
loads (three cheers for lack of rhyme or reason!), but we'd have to do it that
way as well as a result...  Doing that and at the same time getting the document
order thing right will be quite a bit of work. I'd have preferred if IE did not
do that (programming would _not_ be tricky -- that's what the onload event is
for!), since then I'd have had a chance of fixing this bug in some sort of
reasonable amount of time.... <sigh>.
There are scenarios where a JavaScript developer might get into big trouble if
not careful and if a group of scripts are not compiled and initialised in order.

This happens if such scripts are referencing each others' 1) functions 2) values.
Note that they get ready in that order.

Are you sure that an onload event is always a guarantee that all scripts  have
been compiled and initialised?

Which onload event would you use to manage a series of scripts residing in the
head section of a framesetting document?

Sure the frameset onload could be used for that but that's way too late.

I have a faily interesting testcase where onload events seem useless under some
conditions.

I can attach that if you like.
> This happens if such scripts are referencing each others' 1) functions 2)
> values.

This is already broken by the fact that inline defer scripts and external defer
scripts load "out of order"....

In any case, the desired behavior is that described in comment 26, unless I'm
missing something about IE's implementation.
Whiteboard: [HTML4-18.2.1] → [HTML4-18.2.1] See comment 26 for desired behavior
I don't understand why it matters so much how IE has implemented it. Shouldn't
we just follow the spec?
Because the spec says absolutely nothing about any of this. It just vaguely
mumbles something about continuing rendering.  In particular, any answers to the
questions in comment 16 are perfectly fine per the spec.

So given that we can do whatever we want, the obvious thing to do is to not
break pages that _do_ use this attribute and depend on IE's ordering, I would think.
You said yourself that IEs order makes no sense. Given that we can do whatever
we want, the obvious thing to do is to do at as simple as possible IMO. Sites
that depend on IEs loading order are heavily brain-damaged.
"as simple as possible" would be loading in the order in which we get the
data... this is precisely the order bht@actrix.gen.nz objects to.  

Sites that are depending on this are in no way brain-damaged, imo.  The simple
fact is that this is in HTML4 is because IE4 implemented it and MS prevailed on
the HTML WG to include it after that....  So the "standard" behavior is that of
IE4, in essense.
Alias: defer
Just a note from the perspective of a Web Application builder vs a web site for
the masses. We are currently running loadtests against our web app and web app
server. We have found that linking js files causes the pages to load them
serially, halting downloads and giving us perf spikes especially on low
bandwidth connections.

Right now opening a loan loads something like 20 different .js files.
If we can't load them concurrently and we have a 180ms latency, that
adds up to 3.6 seconds just in latency for the js files!!! Not counting
the additional time to download the .htm and .gif files and finally the
3 round trips we have to make to the surrogate!

All of this adds up to a 10 second or more loan open time even on a fat
pipe like a T1 if the latency is high (and 180ms is not that high!!!)

If the defer tag or similar feature would just allow the files to load
concurrently, our performance would rock. :-) I don't pretend to understand the
loading order or it's complexity, but if anyone could add this feature with the
defer tag or perhaps point me to a solution to allow concurrent downloads
without having to have all the scripts inline in a page, that'd be great.

Also, just to expound upon "lack of rhyme or reason". Mozilla seems to load
frames and framesets in the order listed in code. IE on the other hand, loads
them from the innermost child up to the parent, which causes all sorts of issues
when trying to control round trips and load orders on the client. Please don't
follow the IE way on the defer. Moz already has a much better load order than IE
I'd hate to see it get thrown away with the implementation of DEFER
taking.  I'll try to hack on this in the long term.
Assignee: vidur → bzbarsky
Status: REOPENED → NEW
Target Milestone: Future → mozilla1.6alpha
interesting bug...

bz: is it possible to just build up two queues of deferred inline and extern
scripts, store these in the document (or whereever), and then before onLoad
handlers fire, pull down each script and execute?  probably i'm overlooking
something that makes this difficult :-/
Well, there's no win there...  The idea, as I see it, is that you kick off an
async load as soon as you see the <script> tag but you delay evaluation of the
resulting content till onload.  If you just wait till onload to start
synchronosuly fetching stuff, you don't reduce the page load time....

There are various simple conceptual schemes to do this -- the devil is in the
details. ;)
bz: ic... i guess i misunderstood then.  i thought the problem was sync loading
of deferable scripts blocking sync loading of non-deferable scripts.  if that
were the only problem then simple reordering would be enough, right?

also, you might want to watch out for the particularly nasty case of the same
extern script being loaded twice on a page (not that that should be common, but
maybe some misconfigured page authoring tool), one defered and one not defered.
 if you encountered the defered one first and then say suspended it via
nsIRequest::suspend, then second request would get blocked waiting for access to
the cache (only one writer per entry at a time in the cache).  using suspend
would not be ideal for this reason as well as others.  the suspended JS channel
could not be used to download other things, for example.
Good point; I guess the right way to do it is to load the script completely and
then just defer evaluation till later.
Boris' attachment attempted (and failed) to load an external file. The file was
missing and the attachment didn't work.

Why do we need defer?

Defer can be used as a performance-enhancer:
http://msdn.microsoft.com/workshop/author/perf/perftips.asp#DEFER_Your_Scripts
http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/defer.asp

As for top 100 sites, I've seen defer used on microsoft.com before. Defer
definitely isn't  used as often as it could/should be. It's often overlooked
and not widely known.
Attachment #90760 - Attachment is obsolete: true
Keywords: testcase
Target Milestone: mozilla1.6alpha → mozilla1.7alpha
In my web applications, I retrieve source (mixed html/scripts) from the server 
using xmlhttp and then insert these into designated DIV tags. I don't want to 
use IFRAMES for various reasons. This works well in IE but not in Mozilla. In 
Mozilla it just doesn't recognize any scripts that is included through this 
method.

Sample program (from M$ site):



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>InsertScript Sample</title>
<script>
function insertScript()
{
var sHTML="<input type=button onclick=" + "go2()" + " value='Click Me'><BR>";
var sScript="<SCRIPT DEFER>";
sScript = sScript + "function go2(){ alert('Hello from inserted script.') }";
sScript = sScript + "</SCRIPT" + ">";
var a = document.getElementById("ScriptDiv");
a.innerHTML = sHTML + sScript;
}
</SCRIPT>
</head>

<body onload="insertScript()">

<blockquote CLASS="body">

<h1>Insert Script Sample</h1>
<p>This example uses the <b>innerHTML</b> property to insert script into the 
page.</p>

<div ID=ScriptDiv></div>

</blockquote>
</body>
</html>
Pieter, see bug 147581.  Does IE evaluate scripts in innerHTML only if they have
"defer" set or something?
Target Milestone: mozilla1.7alpha → Future
Note to self: it seems IE's behavior is just wacko (see
http://www.websiteoptimization.com/speed/tweak/defer/).  Probably best to just
ignore it.
Severity: normal → enhancement
QA Contact: moied → nobody
Summary: RFE: scripts with defer attribute not deferred → scripts with defer attribute not deferred
maybe a stupid question and sorry for the bugspam if I am wrong. If this is in
the standard specs, why is this bug then marked as an enhancement?
Have you actually read the spec, perhaps?  This attribute tells the UA that it
may do something if it feels like it.  It does not require doing anything.
One other issue that shaver mentioned on IRC today:  what should happen if the
DOM is modified on a page with defer scripts?  That is, if a deferred <script>
is removed from the DOM before the script has executed, should it still execute
when it normally would have?

On a separate issue, shaver says that as he recalls deferred scripts ran the
first time any script ran after they were loaded (including <script> and on*
handlers).  This also needs testing....
Keywords: qawanted
Frankly I recommend WONTFIX. Authors can get reliable "defer" behaviour using
document load event listeners. There doesn't seem to be much point in having an
attribute to do this. I'm tempted to propose just deprecating the attribute in
the WHATWG drafts.
Ian, see comment 36, where I already addressed that suggestion once....
Sorry, missed that.

So the idea here is by implementing this attribute, we would get a performance
win on pages that fetch remote scripts and mark them "defer"?

Do we really care enough? It doesn't seem like there are that many such pages. I
can't think of a single time I've seen it in the wild. I'd have thought the gain
in implementing this would be outweighed by the cost of the increased complexity
and footprint of the codebase (even if the difference was minute...).
There's a reason this hasn't been a top implementation priority... ;)
... ditto (what Boris said) ...

There isn't much value in making this work.... IMO there are many more useful
things to work on. 
(In reply to comment #46)
> Frankly I recommend WONTFIX. Authors can get reliable "defer" behaviour using
> document load event listeners. There doesn't seem to be much point in having an
> attribute to do this. I'm tempted to propose just deprecating the attribute in
> the WHATWG drafts.

I will do my best to explain.

A developer could use "load" event listener on the window and create a script
element.

if(window.addEventListener)
   window.addEventListener("load", addScript, false);
else if(window.attachEvent)
   window.attachEvent("load", addScript);

But then we developers have to write more code and that would take away from
performance, real and perceived. 

It would be more convenient for a developer to use the defer attribute then to
write extra code to simulate the effect.

Although I admit that defer is not used often enough, it a is useful feature,
nonetheless. 

Many other dom features that are supported by Mozilla are useful, but not used
because of lack of support in IE. This bug is just a role reversal, with IE
being the compliant browser for this feature. 

Boris -> ...if a deferred <script>
is removed from the DOM before the script has executed, should it still execute
when it normally would have?

No. Once a script has been removed, it cannot be interpreted (a script must be
interpreted before it is executed). The script element and it's functions should
no longer be available.
> No. Once a script has been removed, it cannot be interpreted

Is this IE's behavior in the scenario in question?

What about deferred scripts that are executed earlier removing deferred scripts
that were going to execute right after them?

Finally, what about having two inline defer scripts, where the first modifies
the text in the second.   What gets executed?  The text that was there when the
script was first parsed, or the new text?

(These are all questions about what IE does, not what people want to happen.)
This is a demo to show that IE doesn't wait till the end to process deferred
scripts - it only waits till the non deferred scripts are done.  OK, everybody
already knew that (well, I hope not, because it's not true), but I thought it
would be nice to isolate it so that there's no confusion on this point: defer
is not to be used to avoid race conditions with page parsing.  Further
attachments intend to show the generalization of what this page demos.

Csaba Gabor from Vienna
Firefox won't emulate IE perfectly, I hope, if it puts in defer support.  This
weird IE bug will also be a good test case to make sure Firefox handles a
deferred javascript: protocol.	Seems that IE has a conflict modifying the DOM
if there's an earlier javascript: protocol.

This came about because the javascript protocol is useful for constructing self
contained test cases.  Fortunately, IE had no problems when setting the src of
script elements to javascript: protocols via the DOM.

Here is the code.  To eliminate the IE bug, you must either remove the defer or
 comment out the document.getElementById line:
<html><head><title>Defer testing</title>
<script type='text/javascript' defer id=scriptDeferredSrc1
	src='javascript:"alert(&#39;script loaded&#39;)"'>
</script>
</head><body>
<table border id=table><tr><td>&nbsp;</td></tr></table>
<script type='text/javascript' id=scriptImmediateInline>
    var one=2;	  // dummy line
    document.getElementById('table').rows[0].cells[0].innerHTML =
	  "Inline immediate script has loaded";
</script>
</body>
</html>
appendInfo('immediate SRC=... loaded')

This is a one line external .js file needed for the MainEvent attachment to
answer Boris' questions.
Firstly, the basic algorithm mentioned in comment 26 (and then comment 42) is
incorrect.  Closer seems to be:

1.  Parse nondeferred scripts till an external or the last script is
encountered
2.  Fetch and execute all scripts encountered to that point.  Continue with 1.

Script elements are placed into the DOM when they are encounterd going through
1. and 2.  The fetching is asychronous (you can't know when files are going to
come in), but it explains the earlier conjecture: deferred inline files should
always come back before external files.

If you have InlineImmediate, InlineDeferred, InlineImmediate2 then when the
first one is hit, there will only be a script element from InlineImmediate and
then when InlineImmediate2 is hit, you have a reference to all three.

To answer the three questions in comment 52:
1.  If you nuke the deferred script element before it executes, it won't
execute
(see Inline Deferred 6 - this causes Firefox an error, by the way).
2.  Um, same story except it's not as safe, because all the deferred scripts in
a block (between external immediates) are fetched asynchronously.  Now
presumably(!), the inline deferred scripts in this block will be returned in
file order.
3.  This is more interesting.  First off, I tried modifying the .src and there
was no problem with that.  If the src is modified before the script is
executed, the new .src is used.  A script can similarly modify is own .src.
Danny Goodman says that modifying .text in IE will do it but won't have any
effect.  Ha ha.  In my IE it's exactly the opposite - you get double.  Seems
like changing the text on any script element will actually execute the script
you're trying to stuff whether or not the element is already loaded.  So in the
case of a deferred inline script, you get one execution on account of changing
the text and one on account of the deferred script still needs to execute. 
That's just wrong.

Other oddities.  If you open the attachment in Firefox, then the
DeferredInline3 script doesn't like either of the first two things it has to
do: deleting DeferredInline3 or modifying the text of DeferredInline6 because
those items are not yet in the DOM.  Firefox doesn't show the 10th script name
(DeferredInline6) - not sure what's happening there.

Modifying the defer property to false did not seem to change its status as far
as IE was concerned, despite what Danny Goodman claimed about it being a read
write property.

By the way, how come you can't get the contents of an external (src=...) SCRIPT
element via the DOM?

My opinion:  It's important to implement defer because it will gain a noticable
speedup on some sites.	However, subject to the discussion above, noone seems
to be using the exact order that deferred script arrive in.  The point is that
even if what is implemented is different from Microsoft, the number of sites
that will break as a result ought to be miniscule because chances are small
that people are making use of unpublished, unguaranteed arrival rates of the
the various deferred scripts.

Therefore, any reasonable implementation will be reasonable.  Furthermore, I
would argue that Microsoft's implementation is not as efficient as it might be.
 For example, suppose that an alert box appears in the first inline immediate
script.  For this, they would suspend bringing in all other scripts (actually,
I'm not sure I tested that so sorry if I'm messing up this argument)?

What I would do:  Defer means Asychronous (and the only thing asynchronous
scripts can count on is that they get executed before the document.onLoad
fires).  As you go through the page and encounter a script, it gets categorized
as Sychronous (immediate) vs. Asychronous (defer) and added as an element to
the DOM (in encountered order).  This is consistent with IE.  If it's
asychronous, start the process to 'bring the file in' (though not execute it). 
If it's sychronous inline execute it.  If it's synchronous external, (1) start
off a process to get the file, and (2) continue parsing so as to identify any
other files that need to be brought in, and (3) while there is time, execute
any waiting deferred script.

I've actually not used defer in practise, but it would be nice if some of the
things that were asked in testing with IE (especially being able to set src or
text) were possible with Firefox (and more importantly, using the current <Base
href=...> value)

Finally, I mention one other thing.  I went to the site in comment 42 and did
their little test.  I am getting Inline Body AFTER Inline Body Deferred EACH
TIME.  That's the reason I said 'Closer seems to be' at the very beginning,
because what I proposed doesn't match observed behaviour on their site either. 
It does, however, match the proposed algorithm that I gave at the end here.  I
think that while they are waiting on a sychronous external request to come
through, they start taking care of backed up deferred scripts and when they run
out of those they continue forward bringing in (and executing) deferred scripts
- since (to my mind) they're asychronous, that makes it OK to bring them in
early (as long as there's no sychronous script ready to be executed).

Csaba Gabor from Vienna
(In reply to comment #56)
> 1.  Parse nondeferred scripts till an external or the last script is
> encountered

What does "last" mean here, exactly?  There's no good way to determine this that
I can see...

> but it explains the earlier conjecture: deferred inline files should
> always come back before external files.

Why?  If the external fetch is async, it could come back before the inline
script is even parsed.

Or are you saying that IE defers not just script execution but also fetching the
script?

> If you have InlineImmediate, InlineDeferred, InlineImmediate2 then when the
> first one is hit, there will only be a script element from InlineImmediate and
> then when InlineImmediate2 is hit, you have a reference to all three.

It's not clear to me what this is saying....

> 2.  Um, same story except it's not as safe, because all the deferred scripts
> in a block (between external immediates) are fetched asynchronously.

So they can execute in non-document order?  (Note that that's not what earlier
testing showed.....)

> the number of sites that will break as a result ought to be miniscule

Only because the number of sites using "defer" is miniscule...

> because chances are small
> that people are making use of unpublished, unguaranteed arrival rates of the
> the various deferred scripts.

This is the web. Trust me, people are depending on the exact undocumented
behavior...

> If it's synchronous external, (1) start
> off a process to get the file, and (2) continue parsing

No can do -- synch external scripts can do document.write(), which means no
parsing can happen till after that script has executed.

Your testcases would be a lot easier to read if they would clearly indicate,
when the testcase is loaded, which order the scripts executed in (and if the
comments in the testcase would clearly indicate which order the scripts execute
in in IE).
A good online test case is at:

  http://www.websiteoptimization.com/speed/tweak/defer/test/

It would have been better if it had "onload" in the game too.  Am I right that
even when deferred, deferred scripts should be loaded before "onload" still?  It
makes a lot of sense that way, and not much otherwise.
Mmm.... that testcase's image shows an order different from that which was
conjectured earlier in this bug.  Is that order correct?  That is, is there
really the wackiness with inline deferred scripts that that testcase shows?
As per my earlier comment, "defer" won't be in WHATWG draft (unless someone
argues for its return). It is very rarely used. I suggest WONTFIX. I don't think
any improvement we would get would justify the implementation cost and the
increased codebase complexity.
I agree with Ian -- WONTFIX is best. This really provides no compelling
benefits....  
i'm sad to see that DEFER still isn't supported in Moz/FF.

i had a problem with some HTML and "JavaScript" that needed to be moved from a
hidden frame into a web-apps main frame via innerHTML. <script> blocks won't get
executed this way neither in IE nor Moz.

but in IE it can be achieved with a DEFER set.

see http://msdn.microsoft.com/workshop/samples/author/dhtml/refs/insertScript_2.htm

as an example.

i found a workaround for my actual problem but that ugly ".eval()" in firefox i
had to use looks awful compared to the deferred script in IE :(
If you createElement() a new <script> element and insert the script into that
then insert the element into the document, that should work.
(Having said that I can't really see any real use case for doing that.)
Not getting to this any time in the foreseeable future (this year, at least).
Assignee: bzbarsky → nobody
Priority: P3 → --
Target Milestone: Future → ---
A very common (f not the most common) use is to make pages appear on the screen
faster. Without this working, Mozilla/Firefox just performs badly and users
won't know why.

It was suggested to move the script to the end of the document.

Not possible with <frameset>. The dilemma is that browsers ignore all scripts
after <frameset>.

Delaying a frameset is the worst thing to do as it already suffers from delays
due its own nature.
Were a content management/provider for people wishing to personalize messaging
to their users.

The defer attribute is used in our case to make sure that our remote snippet
does not affect user's experience when loading our customer's page while our
servers are slow or down.

With IE, this works extremely well since the page will render weather or not our
servers are responding adequately.

It would be great to have the same robustness with FF.
defer is the part of HTML 4.01 specification so Moz
should start support at last!

Here is the life example of 'defer' use for me:

I have the web page which loads several large js files with pure data via

script.setAttribute("src", src);
script.setAttribute("defer", true);
document.body.appendChild(script);

and for the same page I'am catching onload event.

The problem is: the onload event fires only after all
scripts finished loading, while I need it just after doc.
body finished loading. 'defer' helps me greatly in IE,
but not in Mozilla!


*** Bug 306199 has been marked as a duplicate of this bug. ***
I've read the conversation on this topic
with the main idea that the implementation of 'defer'
is a complex task.

I'am failing to understand why.

From my view it is as much easy as the original
implementation of, say, async "onfocus" event firing.

The internal async event, for ex named "__internal_execute_loaded_script"
should be posted to internal window event message queue after the .js file
is fully loaded and handled the same way, say, the async "onfocus"
event are handled and dispatched to the user space if asked to.
http://dean.edwards.name/weblog/2005/09/busted/

And

http://dean.edwards.name/weblog/2005/09/busted2/

Workaround for mozilla to provide the desired effect.
*** Bug 311276 has been marked as a duplicate of this bug. ***
One of the questions put forth by Boris is how defer actually works in IE.  From
what I remember of tests I did several months back, defer in the <head> section
is completely ignored and only has effect when it appears in the <body> section.
 Go figure.

Csaba Gabor from Vienna
This is not really true. At least in IE 6.0 scripts in <head> are deferred. I
will post an example soon
Harrumph.  This is what happens when one doesn't test one's statements
thoroughly before posting.  The following demonstrates that Ivan in comment 74
is correct:

<html><head><title>Defer test</title>
<script defer type='text/javascript'
        src="javascript:'alert(&quot;script 1&quot;)'"></script>
</head>
<body>
<script type='text/javascript'
        src="javascript:'alert(&quot;script 2&quot;)'"></script>
</body>
</html>

The above page will show script 2 first in my IE6 on Win XP Pro before showing
script 1.  Of course, FF shows script 1 first.

At the same time, I'm sure there was some distinction between defer in the head
vs. body when I was conducting my tests.  That'll take some time to review, but
if I figure it out I'll post back.
*** Bug 338806 has been marked as a duplicate of this bug. ***
FYI: based on author feedback, I plan to reverse engineer this and spec it in the WHATWG spec in due course.
See also bug 364315, "Speculatively load referenced files while 'real' parsing is blocked on a <script src=> load".  That would solve some of the same latency issues on sites that don't or can't use the defer attribute.
Steps to reproduce:

<script type="text/javascript" defer>
function ha8validate(p5event) { return true }
document.forms[0].onsubmit = ha8validate
</script>

This script fails because document.forms[0] does not exist yet.
It would exist if the script were properly deferred 
(and, of course, if the body contains a form).
WHATWG spec is updated, by the way, and defines how this should work now, in extreme detail. Let me know if you see any problems with it.
'blocking1.9=?':
As I guess it's too late for 1.9.0.0,
I'm looking for 'wanted1.9.0.x' or 'wanted‑next'...
Severity: enhancement → normal
Flags: blocking1.9?
Keywords: qawanted
QA Contact: nobody → layout
Whiteboard: [HTML4-18.2.1] See comment 26 for desired behavior → [HTML4-18.2.1] [ie-parity] [See comment 26 & 80 for desired behavior]
Not blocking 1.9.  Really too late. 
Flags: blocking1.9? → blocking1.9-
Flags: wanted1.9.1?
Yes, definitely wanted for 1.9.1
Every millisecond you can save is good to save, and that's also for the sake of those who care to program correctly (their scripts).
Ok.  Getting this on the list for 1.9.1.  Assigning to Sicking.  Apparently this is only about a days work for a decent win here.
Assignee: nobody → jonas
Flags: wanted1.9.1? → wanted1.9.1+
Priority: -- → P1
Hixie do you have more detailed stats of the current use of defer tag:

http://code.google.com/webstats/2005-12/scripting.html

On the web?
Assignee: jonas → nobody
Component: Layout → DOM: HTML
QA Contact: layout → general
Assignee: nobody → jonas
Attached patch Patch to fix (obsolete) — Splinter Review
Attachment #331023 - Flags: superreview?(jst)
Attachment #331023 - Flags: review?(jst)
This also tests that deferred scripts execute properly after the document has finished loading.

All the code is exactly the same as previous patch, only the tests have changed.
Attachment #331023 - Attachment is obsolete: true
Attachment #331277 - Flags: superreview?(jst)
Attachment #331277 - Flags: review?(jst)
Attachment #331023 - Flags: superreview?(jst)
Attachment #331023 - Flags: review?(jst)
Comment on attachment 331277 [details] [diff] [review]
Slightly better tests

- In test_bug28293.html:

+function done() {
+  is(res, "ABCDEFGHIJ1abcdefM2g34hi", "scripts executed in the wrong order");

This test should result in something cooler like "One ring to rule them all, ...", I mean, really. :)

r+sr=jst
Attachment #331277 - Flags: superreview?(jst)
Attachment #331277 - Flags: superreview+
Attachment #331277 - Flags: review?(jst)
Attachment #331277 - Flags: review+
Component: DOM: HTML → DOM: Core & HTML
Oooh exciting, a patch.

When applied, will the attached test still give "Pass?" in a popup?
(In reply to comment #89)
> Created an attachment (id=332483) [details]
> When applied, will the attached test still give "Pass?" in a popup?
No it doesn't. Why should it? DOMContentLoaded is dispatched right after
the parsing has finished. Though, seems like the behavior could be
changed pretty easily so that deferred scripts are executed right before
DOMContentLoaded.

Thought it might not. Asked, as both are currently used in pages to delay execution of scripts.
General method is giving IE a seperate defered script block with conditional comments, but I've seen pages with behaviour that reduces to that test.
Don't have particularly strong feelings about the resolution, just thought it's a potential area of change that people should be aware of.
This bug is fixed fwiw, the patch is checked in.

Yes, I decided to dispatch the DOMContentLoaded event before running deferred scripts, couldn't really think of a good reason either way so I just picked one.

Please file a separate bug if you think it change be changed.
Status: NEW → RESOLVED
Closed: 24 years ago16 years ago
Resolution: --- → FIXED
For devmo:

Usually when we parse a <script src="..."> element we immediately stop parsing until the script is fully loaded and executed. The result is that in something like

<script src="A.js">
<script src="B.js">
<script src="C.js">

We don't even start loading "B.js" until A is fully loaded and executed. Same for C which doesn't start loading until A, then B, has loaded and executed. The reason we have to wait is that when the script executes it might expect just the part of the page that is before the <script> to have loaded, and nothing after, especially if the script does calls document.write, it might expect the new content to be inserted right after the <script>.

By setting the defer attribute the page lets us know that the script does not need to execute immediately. Instead the script will execute once the page is fully done parsing. So in a page like:

<html>
  <head>
    <script src="A.js" defer>
    <script src="B.js" defer>
    <script src="C.js" defer>
  </head>
  <body>
    ... page content here ...
  </body>
</html>

We'll start the loads for A, B, and C in parallel and then execute them after parsing the </html> tag.

You can combine both deferred, and normal scripts.

As with normal scripts, deferred scripts always execute in the order they appear in the markup, no matter which order they finish loading.

And like with normal scripts, onload won't fire until all deferred scripts have finished loading and executing.
Keywords: dev-doc-needed
Is there a DOMContentLoaded timing bug out of this?  Seems like we fire DOMContentLoaded after a trailing non-defer <script src=""> was executed, not after we finished parsing the </script> even if it were the last thing in the document.  Should they be the same way?
I would think that would have always been the case.

Non-deferred scripts will halt the parser which means that we won't send the DidBuildModel that lets us know that we've reached the end.

If you think we should change this (which i'm personally not convinced of) it would be an orthogonal bug.
Dcumented here: http://developer.mozilla.org/En/HTML/Element/Script

Feel free to add details if needed.
verified this is working as advertised:
Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b1) Gecko/20081007 Firefox/3.1b1
Status: RESOLVED → VERIFIED
Depends on: 469751
I do not understand the idea of a fixed bug depending on a new bug.  Perhaps it is just me.  Shouldn’t the bug be reopened?
That is the standard convention here since Bugzilla doesn't have a good mechanism for marking bugs as regressions from other bugs. As a result, regressions are marked blocking the original bug under the logic that if this bug were to ever land on a new branch, it would require the fixes from those regression bugs to go in with it.

If you have any other questions, please ask privately so as to avoid off-topic conversation in this bug.
It was mentioned that DOMContentLoaded is fired before deferred scripts. I believe many of us are going to start using defer as an alternative to DOMContentLoaded, so firing the event afterwards requires giving us some way to detect if the script was actually deferred.

What I currently do is include a script with defer, and the first few lines of that script are:

if (addEventListener) addEventListener("DCL", load_complete)
else if (IE) load_complete; // since defer in IE is equivalent to DCL
else onload = load_complete; // fallback for other browsers

It's a fairly clean, simple solution. With DCL dispatched before a deferred script is processed in 3.1, this prevents the script from ever firing load_complete. I certainly wouldn't mind changing the second line to read if (IE || defer.supported), but I'm not aware of how to detect defer support in 3.1.
(In reply to comment #100)
> It was mentioned that DOMContentLoaded is fired before deferred scripts. I
> believe many of us are going to start using defer as an alternative to
> DOMContentLoaded, so firing the event afterwards requires giving us some way to
> detect if the script was actually deferred.

Michael, would you mind filing a new bug about that (i.e. with the summary "<script defer> scripts run after DOMContentLoaded"), and mentioning the number here? We should track that separately.
(I don't know enough about this code to say whether would be easy to fix, or whether we would even want to, but a new bug report is easier to bring attention to than a comment in a closed bug.)
Blocks: 474392
It seems you do not need to check whether defer is supported, 
you just need to check whether the current script is being deferred.  
You can achieve that along these lines:
<SCRIPT TYPE="text/javascript" DEFER><!--
alert(is_deferred) //--></SCRIPT 
><SCRIPT TYPE="text/javascript" ><!-- 
is_deferred = true //--></SCRIPT >
Flags: blocking1.9.2?
Seems broken in Firefox 3.6 beta 5. "Pass?" is given in popup.  It seems with the patch applied it shouldn't.

(In reply to comment #90)
> (In reply to comment #89)
> > Created an attachment (id=332483) [details] [details]
> > When applied, will the attached test still give "Pass?" in a popup?
> No it doesn't. Why should it? DOMContentLoaded is dispatched right after
> the parsing has finished. Though, seems like the behavior could be
> changed pretty easily so that deferred scripts are executed right before
> DOMContentLoaded.
oops missed bug#518104
Flags: blocking1.9.2?
You need to log in before you can comment on or make changes to this bug.