W3C home > Mailing lists > Public > public-html@w3.org > October 2010

Re: Executing script-inserted external scripts in insertion order

From: Hallvord R. M. Steen <hallvord@opera.com>
Date: Sat, 16 Oct 2010 19:52:47 +0900
To: Getify <getify@gmail.com>, "Henri Sivonen" <hsivonen@iki.fi>
Cc: "public html" <public-html@w3.org>
Message-ID: <op.vkn0h9p9a3v5gv@hr-opera.oslo.opera.com>
>> We could just as easily say that feature-test for `async` (and
>> specifically
>> its default value, either true or false) is the feature-test for
>> ordered vs. non-ordered behavior.
>
> I hadn't considered this.

I think this is a good suggestion (think I even brought it up in my  
previous E-mail ;)) - especially good for the browsers who today do  
non-ordered execution and have not implemented 'async' - they can make  
sure it reports 'true' by default for DOM-inserted scripts. If you also  
make sure that happens when Firefox switches to non-ordered behaviour,  
LABjs and friends only have legacy WebKit (support async, default to  
returning 'false' but default to non-ordered) to worry about / UA sniff  
for. And detecting async defaulting to true and setting it to false should  
enforce ordered execution - sounds pretty good to me.

>> >>> <jgraham> Doesn't it make more sense to make preserving order the
>> >>> default
>>
>> It makes more sense to a web performance optimization person like me.

It sort of depends on what the more common use case is - is it loading  
scripts that depend on each other, or loading scripts that happen to run  
on the same web page but are otherwise unrelated?

I'd say scripts that are more important for the user experience and logic  
on a page typically benefit from some predictable execution, and the way  
major sites now use callbacks and load/readyState listeners is a hack to  
work around the non-ordered loading "feature". I'm not entirely convinced  
that forcing pages to rely on call backs and event listeners is good for  
performance overall (though I concur that if we give them an @async  
property that can be set to false, we no longer force them to use  
callbacks).

> Why would that be the performance-savvy default? It seems to me  
> IE/WebKit behavior is more performance-savvy when there are at least two  
> non-interacting scripts being downloaded in parallel (e.g. a site  
> functionality script and an advertising script).

Henri: If the site could choose, would it want the browser to spend time  
on executing the site functionality script or the advertising script  
first? Processing the DOM mutations of the ad layout or the logic that  
will make the site respond to the user? With the browser-centric  
performance hat on running scripts as fast as we can get hold of them  
makes sense, but I'm not sure it really gives the best user experience  
overall.

>> However, I do not know if there are really other compelling use cases
>> for the opposite to be default. For instance, if jQuery is injecting
>> scripts and is bothered by some side-effect of them having order  
>> preservation,
>> is
>
> Now you are talking about a different thing: Script-inserted inline  
> script maintaining insertion order relative to script-inserted external  
> scripts.

Interesting that WebKit according to this test gets away with not-ordered  
execution, compat-wise:
http://testsuites.opera.com/script-execution/015.html

> I'm trying to find a solution that satisfies the constraints placed by  
> existing jQuery and the constraints placed by existing LABjs. AFAICT,  
> the jQuery constraint is about how script-inserted inline scripts  
> execute relative to script-inserted external scripts but the LABjs  
> constraint is about how script-inserted external scripts execute  
> relative to each other. Thus, it seems to me that it's possible to  
> satisfy both constraints at the same time. (By making script-inserted  
> inline scripts not maintain order relative to script-inserted external  
> scripts and making script-inserted external scripts with async=false  
> maintain order among themselves.)

I was going to say "don't think we can do that for compat reason" but  
noticed WebKit already does.. ;)

> I think the default shouldn't depend on what makes sense but on what  
> works for existing content.

In this case much (all?) existing content should work with either  
behaviour since Firefox+Opera with their fairly substantial market share  
differs from IE+WebKit.. So we should be able to pick a default based on  
what's more author-friendly.

(However, I have not investigated why exactly HTML5 parsing made you run  
into a bug that made you want to implement non-ordered execution. I may be  
missing something regarding why non-ordered is a better/easier choice for  
a UA that supports HTML5 parsing. Guess I will find out some day.. :-p)

> My point is that if existing content can't rely on a characteristic, the  
> spec doesn't need to provide that characteristic as a default.

..unless it's considered better on its own merits..

>  1) Blocking script-inserted inline scripts when there's a pending  
> external non-async script. This characteristic is so undesirable that  
> it's what prompted the change in Gecko.

(An equivalent issue just caused me problems when enabling Facebook's  
@mentions with Opera's site patching, so I agree entirely that this is a  
bad thing.. And it seems we can follow WebKit and do it differently.)

>  2) Blocking parser-inserted scripts when there's a pending  
> script-inserted external non-async script. This characteristic is  
> undesirable, because it put Gecko at a performance disadvantage compared  
> to IE/WebKit and, AFAICT, the stronger guarantee that Gecko used to  
> provide was useless to sites, because there was no way to make use of  
> and have the site work with IE or WebKit, too, since the behavior is (or  
> am I wrong?) impossible to emulate by adding more scripting.
>
>  3) Blocking a script-inserted external non-async script on a pending  
> script-inserted external non-async script. As I understood from your  
> blog, this is the only one of the three characteristics that LABjs  
> relies on. Correct? Thus, compatibility with existing content makes it  
> desirable. However, it's slightly undesirable in the case where there  
> are independent legacy (i.e. legacy in the sense that the author didn't  
> know about async and didn't set async=true) scripts loading in parallel,  
> e.g. a site functionality script, advertising script and analytic script.


> Considering the slight undesirability of characteristic #3 in the case  
> of independent legacy scripts, I think it's not safe to expect that IE  
> or WebKit would implement characteristic #3 (so that LABjs could rely on  
> it in IE and WebKit in the future) simply because the WG speccing it. In  
> the case of WebKit, there's evidence of prioritizing performance over  
> spec correctness (see  
> http://weblogs.mozillazine.org/bz/archives/020267.html ) in the sense of

(Aside - thanks for the link, bz mentions Opera in a way made me really  
proud even though my work rarely touches the layout engine ;) )

> Hallvord R. M. Steen wrote:
>> 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.
>
> Do you remember why aol.com or CNet broke and what they did not break in  
> IE or WebKit?

Sorry to wave around somewhat vague assertations there. I've looked things  
up to see if they are actually relevant..

CNet (and a few other sites back then - probably more than I managed to  
analyze because those problems typically were hard to debug) broke because  
we ran document.write() inserted external scripts immediately. It seemed  
like a good idea at the time (since document.write() internal scripts run  
immediately, it was sort of seen as the most predictable way to do it).  
However, then CNet came along to do

document.write(<script src=some/script/depending/on/args/variable.js>)
args='foo'

and we threw an exception inside the external script because 'args' was  
not defined when it ran.

The problem on AOL and some other sites (a problem which is still with us  
actually) is caused by blocking *parsing* when exernal scripts are  
inserted through the DOM. Turns out a few sites rely on being able to see  
elements after the script that inserts the external script (but does AOL  
really work if e.g. the external script is cached? By my testing it's  
entirely random how much further in the DOM the parser gets when the  
script runs..). Has nothing to do with order of scripts, so forget I  
mentioned it.

>> > It doesn't make sense to make script-inserted inline script maintain
>> > order relative to script-inserted external scripts by default.

>> It's not ideal, but over the years we (Opera) have concluded that this
>> is required for web compat reasons,
>
> How can it be required for Web compat when IE and WebKit don't do it. I  
> could buy an explanation that enough sites put IE on a different code  
> path from everyone else, but if that were the explanation, how could  
> WebKit have gotten away with cloning IE rather than Gecko?

Re-reading some old bugs. We were forced to make a major change a while  
ago (we used to run external scripts as soon as they were inserted into  
the DOM, blocking appendChild() until the script was downloaded and run -  
by the time that behaviour was changed it was causing trouble for Dojo,  
YUI and breaking Facebook's new user registration form.. ). It caused  
regressions and various (mis)behaviours during several months, but  
actually I don't find bugs related to non-ordered execution of  
DOM-inserted scripts. We had problems with document.write and order that  
were related to weird things sites do, we had problems with DOM-inserted  
but all those were appearently weird things Opera did so not really  
relevant :).

>> 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
>> }
>
> async defaults to false in WebKit nightlies, so if they ship a release,  
> the test you suggest will de facto become unreliable.

But if they can fix it, LABjs can use browser sniffing to target  
unreliable editions ;)

>> How long did it take you from releasing the relevant beta
>> build to the Twitter widget bug report?
>
> Roughly one month from the start of the beta exposure.
>
> The HTML5 parser was enabled by default on 2010-05-03. The first beta it  
> shipped in was released on 2010-07-06. The bug was filed on 2010-08-09.

Interesting, thanks.

-- 
Hallvord R. M. Steen, Core Tester, Opera Software
http://www.opera.com http://my.opera.com/hallvors/
Received on Saturday, 16 October 2010 10:53:04 UTC

This archive was generated by hypermail 2.3.1 : Monday, 29 September 2014 09:39:20 UTC