Note: There are a few cases of duplicates in user autocompletion which are being worked on.

scripts with defer attribute not deferred

VERIFIED FIXED

Status

()

Core
DOM: Core & HTML
P1
normal
VERIFIED FIXED
18 years ago
3 years ago

People

(Reporter: Ian Graham, Assigned: sicking)

Tracking

(4 keywords)

Trunk
dev-doc-complete, html4, perf, testcase
Points:
---
Dependency tree / graph
Bug Flags:
wanted1.9.1 +
blocking1.9 -

Firefox Tracking Flags

(Not tracked)

Details

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

Attachments

(7 attachments, 3 obsolete attachments)

(Reporter)

Description

18 years ago
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.

Comment 1

18 years ago
clayton: what's your call on supporting this?
Assignee: rickg → clayton

Comment 2

18 years ago
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
(Reporter)

Comment 3

18 years ago
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.

Comment 4

18 years ago
Vidur -- is this part of the DOM spec? If so, the I think we may need to support 
it.
Assignee: rickg → vidur

Comment 5

18 years ago
Hmm -- trying to reassign to vidur so he can make the call.

Comment 6

18 years ago
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
Last Resolved: 18 years ago
Resolution: --- → LATER
Summary: defer attribute not supported on script elements → RFE: defer attribute not supported on script elements

Updated

18 years ago
Keywords: verifyme

Comment 7

17 years ago
massive update for QA contact.
QA Contact: petersen → lorca

Comment 8

17 years ago
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: 7954, 41368
Keywords: verifyme → html4

Comment 11

16 years ago
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

Updated

16 years ago
OS: Windows 98 → All
Hardware: PC → All

Updated

16 years ago
QA Contact: bugzilla → gerardok

Comment 13

16 years ago
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]

Updated

15 years ago
Keywords: perf

Comment 14

15 years ago
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?

Comment 15

15 years ago
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

Comment 16

15 years ago
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)

Comment 17

15 years ago
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>

Comment 18

15 years ago
That produces no output or that throws a "test is not defined" error?

Comment 19

15 years ago
Also, it does not matter what the documentation says; what matters is what the
actual behavior is.... :(

Comment 20

15 years ago
No output and a "'test' is undefined" error popup, if script error notification is turned on.

Comment 21

15 years ago
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.

Comment 22

15 years ago
> 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).

Comment 23

15 years ago
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.

Comment 24

15 years ago
Created attachment 90759 [details]
Testcase for this bug...

Comment 25

15 years ago
Created attachment 90760 [details]
Real testcase for this bug
Attachment #90759 - Attachment is obsolete: true

Comment 26

15 years ago
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>.

Comment 27

15 years ago
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.

Comment 28

15 years ago
> 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

Comment 29

15 years ago
I don't understand why it matters so much how IE has implemented it. Shouldn't
we just follow the spec?

Comment 30

15 years ago
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.

Comment 31

15 years ago
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.

Comment 32

15 years ago
"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.

Updated

15 years ago
Alias: defer

Comment 33

15 years ago
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

Comment 34

15 years ago
taking.  I'll try to hack on this in the long term.
Assignee: vidur → bzbarsky
Status: REOPENED → NEW
Target Milestone: Future → mozilla1.6alpha

Comment 35

15 years ago
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 :-/

Comment 36

15 years ago
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. ;)

Comment 37

15 years ago
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.

Comment 38

15 years ago
Good point; I guess the right way to do it is to load the script completely and
then just defer evaluation till later.

Comment 39

14 years ago
Created attachment 122110 [details]
Test of defer attribute

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

Updated

14 years ago
Keywords: testcase

Updated

14 years ago
Target Milestone: mozilla1.6alpha → mozilla1.7alpha

Comment 40

14 years ago
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>

Comment 41

14 years ago
Pieter, see bug 147581.  Does IE evaluate scripts in innerHTML only if they have
"defer" set or something?

Updated

14 years ago
Target Milestone: mozilla1.7alpha → Future

Comment 42

14 years ago
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.

Updated

14 years ago
Severity: normal → enhancement
QA Contact: moied → nobody
Summary: RFE: scripts with defer attribute not deferred → scripts with defer attribute not deferred

Comment 43

13 years ago
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?

Comment 44

13 years ago
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.

Comment 45

13 years ago
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.

Comment 47

13 years ago
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...).

Comment 49

13 years ago
There's a reason this hasn't been a top implementation priority... ;)
(Reporter)

Comment 50

13 years ago
... ditto (what Boris said) ...

There isn't much value in making this work.... IMO there are many more useful
things to work on. 

Comment 51

13 years ago
(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.

Comment 52

13 years ago
> 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.)

Comment 53

13 years ago
Created attachment 178146 [details]
Proof that defer doesn't wait till the end

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

Comment 54

13 years ago
Created attachment 178150 [details]
An IE defer bug with the javascript: protocol

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>

Comment 55

13 years ago
Created attachment 178151 [details]
one line external javascript for the MainEvent

appendInfo('immediate SRC=... loaded')

This is a one line external .js file needed for the MainEvent attachment to
answer Boris' questions.

Comment 56

13 years ago
Created attachment 178171 [details]
MainEvent - Answers for Boris

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

Comment 57

13 years ago
(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).

Comment 58

12 years ago
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.

Comment 59

12 years ago
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.
(Reporter)

Comment 61

12 years ago
I agree with Ian -- WONTFIX is best. This really provides no compelling
benefits....  

Comment 62

12 years ago
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.)

Comment 65

12 years ago
Not getting to this any time in the foreseeable future (this year, at least).
Assignee: bzbarsky → nobody
Priority: P3 → --
Target Milestone: Future → ---

Comment 66

12 years ago
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.

Comment 67

12 years ago
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.

Comment 68

12 years ago
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. ***

Comment 70

12 years ago
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.

Comment 71

12 years ago
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.

Comment 72

12 years ago
*** Bug 311276 has been marked as a duplicate of this bug. ***

Comment 73

12 years ago
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

Comment 74

12 years ago
This is not really true. At least in IE 6.0 scripts in <head> are deferred. I
will post an example soon

Comment 75

12 years ago
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.

Comment 78

11 years ago
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-

Updated

9 years ago
Flags: wanted1.9.1?

Comment 83

9 years ago
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

Comment 85

9 years ago
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
Created attachment 331023 [details] [diff] [review]
Patch to fix
Attachment #331023 - Flags: superreview?(jst)
Attachment #331023 - Flags: review?(jst)
Created attachment 331277 [details] [diff] [review]
Slightly better tests

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+

Updated

9 years ago
Component: DOM: HTML → DOM: Core & HTML

Comment 89

9 years ago
Created attachment 332483 [details]
Early content-loaded corner case semi-test

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.

Comment 91

9 years ago
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
Last Resolved: 18 years ago9 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
Depends on: 453801
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.
Keywords: dev-doc-needed → dev-doc-complete
Depends on: 461555
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
Depends on: 469769
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.

Comment 100

9 years ago
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.)

Updated

9 years ago
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 >
Alias: defer

Updated

8 years ago
Flags: blocking1.9.2?

Comment 104

8 years ago
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.

Comment 105

8 years ago
oops missed bug#518104

Updated

8 years ago
Flags: blocking1.9.2?
You need to log in before you can comment on or make changes to this bug.