Re: Executing script-inserted external scripts in insertion order

Hi Henri,
thanks for a really good writeup. I've written a substantial number of  
tests for script execution order to explore what other browsers do, and  
have some influence on what Opera will implement for the future. We've  
arrived at the current implementation through years of trial, error and  
broken sites (some important like aol.com and CNet) so we're naturally  
worried about making even small changes here. To drop insertion order  
execution seems like a MAJOR change. It also makes script execution more  
unpredictable and more likely to end up in race conditions. (For example,  
if a site is only tested on broadband it might fail completely on first  
load on a connection with different timing characteristics).

It does not make much sense to me to implement one attribute to opt out of  
source order execution ('async') and another one to opt IN because the  
default behaviour isn't default after all.. ;) But that was pretty much  
what James Graham said on IRC and the response was

> "Please leave your sense of logic at the door, thank." :-)

Not sure about that - script execution is now getting very complicated  
 from an author point of view, and ease of authoring is one of our main  
concerns..

> More seriously, it really doesn't make sense to make script-inserted  
> external scripts and parser-inserted scripts to maintain order by  
> default (probably not at all). Since WebKit and IE taken together have  
> non-trivial market share, Web authors can't rely on the stronger  
> ordering provided by Opera and Firefox 3.6. When authors have to develop  
> for the weaker guarantee anyway, the result is that authors can't  
> benefit from the stronger guarantee but it still carries a perf penalty.  
> Specifically, Gecko (and presumably Opera, though I didn't investigate)

(As an aside, Opera currently blocks even parsing on a script-inserted  
external script, so performance-wise we're at an even worse disadvantage  
than Gecko when this technique is used..)

> loses to IE and WebKit in perf if the page author follows the advice  
> from  
> http://www.nczonline.net/blog/2009/07/28/the-best-way-to-load-external-javascript/  
> but also has an additional parser-inserted script after the performance  
> recipe.

His explicit advice is to keep these scripts at the very end of the BODY  
element, and - perhaps more implicitly - use loadScript() to include all  
other external scripts. In other words, if web authors don't follow his  
advice on improving performance correctly they won't benefit from improved  
performance.. ;)

> It doesn't make sense to make script-inserted inline script maintain  
> order relative to script-inserted external scripts by default. The  
> reason is that it's bad when a typically synchronous operation becomes  
> asynchronous depending on what has happened before. In the typical case,  
> a script-inserted inline script is evaluated synchronously. However, if  
> order is maintained as in Firefox 3.6, the operation becomes  
> asynchronous if there happens to be a pending external script.

It's not ideal, but over the years we (Opera) have concluded that this is  
required for web compat reasons, and we (the WG) have already solved this  
problem by spec'ing the async attribute. For example jQuery's global eval  
method can simply set async on the created script, and it won't be  
affected by pending external DOM-inserted scripts after all. This would  
fix your Twitter widget bug (585620), right?

Regarding the 'ordered' attribute (and regardless of what I think makes  
sense ;)), I think the semantics we're looking for is a way to mark one  
specific script as "this is a library later scripts will rely on". It  
seems to fit the semantics, LABjs's API, and the use case better to have  
an attribute called 'blocking'. Script-inserted external scripts with  
'blocking' set would block execution of other (inline and external or just  
external?) scripts until the blocking script was done executing.

> Would WebKit and IE implement the spec if it required script-inserted  
> external scripts that don't have the async attribute to maintain order  
> among themselves (with the async attribute as an opt-out mechanism for  
> requesting unordered behavior) and also required at least  
> type=script/cache to be fetched? If WebKit and IE were willing to do  
> this, adding the 'ordered' DOM property that I proposed would not be  
> worthwhile. However, then the question would be: How could a LABjs  
> version released before WebKit or IE complied with the edited spec  
> capability-sniff ordered execution so that a LABjs version written after  
> the spec change but before WebKit/IE changes would put WebKit or IE on  
> the code path the relies on ordered execution once WebKit or IE complied?

We could specify that the async attribute reflects how the browser will  
execute the script?

For example

document.createElement('script').async > false in WebKit (not yet  
supported in IE AFAIK - not tested in IE9 though).

var tmp=document.createElement('script');
tmp.src='foo';
if(tmp.async==true){
	// loading of script-inserted external scripts is unordered by default
}

I have not tested this in Gecko, but it seems like a possible capability  
detection approach if we specify insertion order execution as the default  
for script-inserted external scripts.

This is slightly backwards as it doesn't work in today's WebKit-based  
non-insertion-order browsers. With Chrome's update regime I'm not sure how  
much of a concern that is for Chrome - seems few worry about coding for  
legacy Chrome versions anyway :). That leaves Safari (and the fact that  
Opera doesn't yet support async so some of the LABjs UA sniffing is still  
required).

> Boris Zbarsky wrote:
>> Yes, which is why in the short term Gecko is doing the willful spec
>> violation thing. Then we'd ship a version that has "ordered" _and_ the
>> spec violation. Then we'd ship a version that just does "ordered" and
>> hope/push for sites to update to a working labjs.
>
> This was my thinking, yes. It's a rather optimistic approach, since it  
> assumes we would be able to get sites to update LABjs and RequireJS  
> *and* that in the meantime more JS code relying on UA sniffing and  
> ordered execution wouldn't crop up.

I think we will find a lot more content that relies on this once we try to  
change it. How long did it take you from releasing the relevant beta build  
to the Twitter widget bug report?

> It may well be worthwhile to consider a pessimistic approach that starts  
> with the assumption that Gecko and Opera won't be able to get rid of  
> ordered execution of script-inserted external scripts that don't have  
> the async attribute and that IE and WebKit won't be able to get rid of  
> supporting preloading text/cache scripts.


-- 
Hallvord R. M. Steen, Core Tester, Opera Software
http://www.opera.com http://my.opera.com/hallvors/

Received on Monday, 11 October 2010 23:22:23 UTC