[whatwg] defer on style, depends

On Mon, Feb 9, 2009 at 7:37 PM, Boris Zbarsky <bzbarsky at mit.edu> wrote:
> Garrett Smith wrote:
>>
>> In general, I want better declarative control over loading external
>> resources. The solution(s) should not cause compatibility problems
>> with existing browsers (because I have to support IE6 and Firefox 2).
>
> Honestly, by the time anything we're discussing now will be shipping in a
> browser Firefox 2 marketshare should be nonexistent.  I can't speak for IE6.
>

I'm optimistic. We can make it so authors can declare that (a)
script/s will not wait for (a) stylesheet? Or declare that a script
will wait for a particular stylesheet (which is something that happens
already).

>> I want the browser to be able to load and run a script without being
>> in the position of trying to determine if it should wait for
>> stylesheet data to complete.
>
> As in you don't want the browser to make this determination, right? That is,
> you know that your script doesn't depend on any style data and you want the
> browser to just run it?
>

In one case, yes.

> I would be fine with a way to flag scripts with that information, though
> there is a catch-22: if you flag such a script and it DOES depend on style
> information, then existing UAs will get it "right" and any UA implementing
> the new spec will get it "wrong".
>

If the page does what it is designed to do, and that the design is
flawed, the page would be broken by design. Designing things to be
broken would be "wrong".

> Of course the same is true for the "flag-the-stylesheet" proposal...
>
>> In browsers that do support defer, the script would run *after* the
>> document parsed, and that would occur after the stylesheet loaded.
>
> I'm not sure why this is a performance problem, per se.
>
>>>> 2) want to load stylesheets later, (infoPanel example)
>>>
>>> Not sure what this example is, or why this is insufficienty served by,
>>> say,
>>> putting the <link> at the end of the HTML (assuming HTML allowed that, of
>>> course).
>>
>> Are you proposing HTML allow that?
>
> That's one possible solution to the issue of starting stylesheet loads as
> late as possible, yes.  It's not a great one a priori, but has the benefit
> of good compat with existing UAs (which you said was a priority for you).
>

Not that I think you are wrong, but that statement ought to be backed
up by some tests.

>> The script could declare whether it needs such resource by its
>> "depends=" attribute. However, browsers today delay (some) scripts
>> from running. Scripts depend on stylesheets; content depends on
>> scripts and stylesheets. Content can contain more scripts. Omitting
>> depends for scripts could not possibly solve the problem for browsers
>> today (because they already depend on stylesheets).
>
> Honestly, I don't think anything would solve the problem for browsers
> _today_.
>

No, just observing that the problem could have been avoided with a
"depends=" attribute, if only such attribute had existed c2000, and
having scripts wait only when depends is set. I like this design.

>> An "independent" attribute on a link says that a browser does not need
>> to wait for that resource to finish loading before it loads other
>> resources (like loading a script). When the parser parses that
>> "independent" attribute, it sets a flag for the browser go ahead and
>> download and run any subsequent script.
>
> That doesn't work for today's browsers, though, just like flagging the
> script doesn't.  Or am I missing something?
>

You got it. It doesn't work for today's browsers. However, it isn't
guaranteed *not* to work by any standard. In fact, browsers behave
differently on the matter. Could this new feature result in breaking
code in older browsers?

Those browsers would load and apply the stylesheet in series. That
would be slower.

A race condition is where the script might run before the sheet loaded.

Developers who don't know that shouldn't use that feature.

The "sad path" -- what can happen when a developer misuses "independent":
Case 1: Developer tests in the browser that supports "independent".
The script runs before the stylesheet loads in browsers that support
independent. The result of the race condition is what the developer
wants. The opposite effect happens in older browser.

Case 2: The author uses "independent" and only tests in browsers that
do not support that feature. When loaded in a newer browser that does
support "independent", the script loads before the stylesheet and the
page does not work as designed.

The problems in case 1 or case 2 could happen today. Browsers today
are inconsistent with waiting for stylesheets to download (try any of
the examples I have provided in Opera, Safari, Firefox, IE).

Developers today blame the browser, or possibly the script when "it
doesn't work".

The happy path:
The "defer" on link and "depends" on script work together. The link is
deferred, then loaded when the script loads.

>> A "nodepends" type attribute on a script would work, too. I like that
>> idea, though it does mean the browser has to do some lookahead (then
>> again, apparently they already do).
>
> What sort of lookahead?  Gecko, for example, just keeps parsing right past a
> stylesheet load.  The only thing we stop the parser for is <script>s,
> because those can do document.write.  And even then, the speculative parser
> continues doing loads past that point.
>
> All that style sheets hold up is the script running, not the script loading
> (in Gecko).  If the script were marked as "doesn't have to wait for
> stylesheets", we could just run it as soon as it loads.
>

You say that stylesheets do not block script loading. That may be true
of "Shiretoko" 1.9.1, however, that is not what I see for Firefox 3.0.
The example I posted shows that stylesheets hold up body content from
rendering. If that content contains a script tag, the script will
*not* load *or* run.

The following example shows this to be true:
http://dhtmlkitchen.com/jstest/block/link-external.html

Here is data taken from Live HTTP Headers.
+---------------------+-------------------------------+
| req                 + HTTP date                     |
----------------------+-------------------------------+
| link-external.html  | Tue, 10 Feb 2009 07:01:13 GMT |
| example.js?top      | Tue, 10 Feb 2009 07:01:13 GMT |
| delay.jsp?ct=text...| Tue, 10 Feb 2009 07:01:13 GMT |
| example.js?bottom   | Tue, 10 Feb 2009 07:01:22 GMT |
+-----------------------------------------------------+

The last request, example.js?bottom exists before the closing body tag.
The HTTP Date of the last request is 8 seconds after the date of delay.jsp.

The only explanation I have for this behavior is that the browser is
waiting for the stylesheet to complete before it requests the script
in the body. That is why it would be better for performance to have
that script prefetched, and prefetching could not be achieved by
placing it in the body.

In Firebug, I see similar results.

Shiretoko 1.9.1 is a different story.

Results using "HTTP Scoop":
+---------------------+-------------------------------+
| req                 + HTTP date                     |
----------------------+-------------------------------+
| link-external.html  | Tue, 10 Feb 2009 19:31:09 GMT |
| example.js?top      | Tue, 10 Feb 2009 07:01:09 GMT |
| delay.jsp?ct=text...| Tue, 10 Feb 2009 07:01:09 GMT |
| example.js?bottom   | Tue, 10 Feb 2009 07:01:09 GMT |
+-----------------------------------------------------+


>>> That's exactly what Gecko does in this case, for what it's worth.  It
>>> will
>>> load the script in parallel, but won't _execute_ the script until the
>>> non-alternate stylesheet has loaded.
>>
>> For a script in the head, that is what Gecko and Webkit will do.
>
> What I said was true for all scripts.  We do not differentiate between
> content in <head> and content in <body> in this regard.
>

In Shiretoko 3.1, true, but in Firefox 3.1, the bottom script is not
loaded. I speculate perhaps because content is not loaded and the
script in the body is treated as content (as are IMG).

http://localhost/jstest/block/link-img.html

>> However, external resources such as SCRIPT or IMG that appear in the
>> BODY will not get requested by the browser until the page content
>> renders.
>
> You mean until all the HTML before the tag has been parsed?  Or something
> else?  There's no dependency between script loading+execution and page
> rendering, in Gecko.  Heck, you can run scripts in a display:none iframe,
> with no rendering in sight.
>

By "all the HTML before the tag has been parsed," I think you mean,
all the HTML before the tag for that IMG or SCRIPT resource. Right? If
I understand you correctly, you are asking me if the resource for that
tag would not load until all the HTML prior has been parsed. Is this
right? Next you're saying that visual display is not correlated to
script loading or script execution. I'm not sure how this is related.
I think I am misunderstanding you.

>> In both cases (head script or body script), the browser will not
>> execute the script until the stylesheet is downloaded. It won't render
>> content that occurs after the script until the script is executed.
>
> That's correct, yes.
>

In Shiretoko, a script, even a deferred script, will not run until the
stylesheet is loaded.

http://dhtmlkitchen.com/jstest/block/link-body-defer-bottom.html
contentLoaded: 5087
onloadFired: 5089
headEnd: 5086

In Shiretoko, that deferred script runs after 5 seconds. That's just
after the stylesheet loads.


>> So what we have here is a daisy chain. Content depends on Script
>> depends on Style. That is very crude order of affairs and offers the
>> developer little control over load order.
>
> Yes, agreed.
>

Can we make an improvement on that, or to make that improvement
configurable to the page author?

>> to fulfill example 2, I would defer the stylesheet, and declare the
>> script at the end depends on it. Before that script could run, the
>> stylesheet would need to be loaded. Since the linked stylesheet is
>> deferred, the body content would render and not be blocked by the
>> linked stylesheet loading.
>
> Ah, that is one thing that Gecko does do: we don't start _layout_ (as
> opposed to parsing) until all the stylesheets in <head> have loaded.
>

For Firefox 3.0, IMG and SCRIPT that are part of the body are fetched
around this time. They are not fetched prior. Why not?

> You can get around this trivially by putting a stylesheet as the first thing
> in <body>; that stylesheet won't block rendering in Gecko 1.9. You get a
> performance hit when the sheet loads, of course, because of the ensuing
> restyle, but you might be ok with that (I presume you are given that you
> want to load the stylesheet after the content has been rendered).
>
> In fact, if you use a <script defer> after the sheet and a sheet at body
> start you'll get the behavior you want in Gecko 1.9.
>

In that case, the link would not block layout. See Example:
http://dhtmlkitchen.com/jstest/block/link-body.html

but the script script would be block subsequent layout for browsers
that do not support defer. Example:
http://dhtmlkitchen.com/jstest/block/link-body-defer.html

If the script is deferred and moved to the very end of the body:-
http://dhtmlkitchen.com/jstest/block/link-body-defer-bottom.html

- the content is displayed, the IMG is loaded and rendered, but the
script is not run until *after* the delayed stylesheet runs.

This would have the dependency effect I wanted (my "example 2"), in Firefox 3.1.

I see a very similar time response effect when moving the deferred
script up to the head, keeping the link in the body. Example:
http://dhtmlkitchen.com/jstest/block/link-defer-top.html

In "Shiretoko" 1.9.1b3pre, a deferred script waits for all stylesheets
to load before running. However, this is not guaranteed behavior in
any standard. It is not what happens in browsers that do not support
defer. Placing scripts before stylesheets and adding defer is not
practical for web compatibility. It would result in poor performance
in browsers that do not support defer and result in divergent
behavior, as mentioned earlier.

> Again, I doubt we can come up with any declarative solution that would work
> with UAs that don't implement defer already....
>
>> Question: When the stylesheet is eventually applied, could the reflow
>> be optimized for performance?
>
> Not easily, no.  Or rather, the reflow already is; the style data
> recomputation is the hard part.
>

What would make it easier? I'd really like to know how to design my
pages so that they are faster and more responsive.

Would it be too outlandish for the link have a "scope" attribute? The
scope could be a selector for a script or element.

>> A deferred a stylesheet would load after the page loads
>
> Note that this is not the behavior deferred scripts have, by the way, at
> least in Gecko.  They load eagerly, but execute lazily...
>

One difference between a script and linked stylesheet is that script
element does not have content that can be accessed by the DOM.

A deferred stylesheet being requested by the browser would not be a
problem. Mozilla already makes predictive fetches for links. However,
if a deferred stylesheet is fetched during loading, should that
stylesheet (and rules.length, etc) be accessible via script in that
time? Should the deferred link fire a load event after the request
completes?

I am interested to hear what you have to say about this.

> -Boris
>

Garrett

Received on Wednesday, 11 February 2009 23:43:37 UTC