Re: [whatwg] defer on style, depends
On Fri, Feb 13, 2009 at 12:34 AM, Ian Hickson i...@hixie.ch wrote: On Mon, 9 Feb 2009, Boris Zbarsky wrote: Ian Hickson wrote: I'm not convinced either of these are really great solutions. I think it'd be better just to have the script itself only block when it hits CSS-dependent APIs (though I recognise that that is a much harder problem in most rendering engines today). I'm not sure how you envision this working. The run-to-completion semantics mean that while the script is working on the API call to return (which means that network events are being processed, etc), the following invariants need to be maintained (list very much not exhaustive): 1) No setTimeout timers fire. 2) No XMLHttpRequest state changes happen. 3) No image load events fire. 4) No stylesheet load events fire (for UAs that implement such an event on their link elements, as Gecko would like to do). 5) No user interaction with the page or other pages that can reach the given page is allowed. #5 makes it unlikely that a UA would want to go this route at all. #4 means that this approach would be incompatible with reasonable style load events... #1, #2, #3 all mean that networking needs to differentiate between the set of stylesheets we're waiting on and everything else. Yeah, fair enough. By the way, the spec doesn't yet require the blocking behavior. I couldn't work out how to do it. Could you elaborate on when exactly in the process the style sheet is waited on? Does it happen for all scripts? For example, if a script inserts a style sheet and then a script, does that script wait for the style sheet to load? On Mon, 9 Feb 2009, Garrett Smith wrote: If I put the script at the bottom of the page, and a linked stylesheet in the head, the script waits for the stylesheet. I want my page to load faster and this feature prevents it. Put the script in the head before the style sheet and use the defer attribute so that it runs the script as if it was at the end of the page. It seems pretty simple to me; if you want the style to be loaded when the script runs, put the style first. If you don't, put the script first and defer it (or mark it async). Why should this not be enough? The implementation might delayed the page from rendering when it sees the stylesheet. That's unrelated to scripts, though, right? If you don't want the script to block page load, then speak to your browser vendor. The spec doesn't require that. The script's defer attribute does not work in a majority of implementations. For such browsers, it makes sense to put the script lower on the page for performance reasons, not before the linked stylesheets. Moving the deferred script from the bottom of the page to the head, just before the stylesheet would mean that those scripts would load first. This would prevent the page content from loading until those scripts had loaded. This would hurt performance in the majority of browsers in use today. Sure, but then the feature you describe doesn't work in today's browsers either, so that seems like a wash. On Mon, 9 Feb 2009, Garrett Smith wrote: There are two/three issues. 1) want to load stylesheets without having scripts block Put the scripts first. Then the scripts block. I explained this and showed this in examples. If the script is deferred, it will wait for the stylesheet. 2) want to load stylesheets later, (infoPanel example) Put the styles later. The script blocks the stylesheet. 3) (2), but want to make sure the stylesheet is loaded before the script runs. Put the styles first. The stylesheet can be placed right before the script which depends on it, right before closing body tag: http://dhtmlkitchen.com/jstest/block/link-script-bottom.html and the result will work in Firefox. However, that does not works consistently in a wide enough range of current browsers. Particularly, Webkit and Opera will alert('loaded') before getting the stylesheet. Example 1: headtitle/title link independent type=text/css ... script.../script I want the browser to: 1) load my stylesheet and then immediately begin to load script in parallel. Put the script first with a defer or async attribute. I have already explained why this is going to make the page functionally inconsistent and hard to maintain across a set of browsers where some browsers have support for defer and others do not. The deferred alert external script will run first in browsers that ignore defer. In browsers that do not ignore defer, (Firefox 3.1 pre) it will run last, after the stylesheet is loaded. Boris explained that current Gecko behavior is that any stylesheet load started by parsing a style or link tag will increment a counter on the script loader object for that document. This also explains why putting deferred scripts first will hurt performance in both cases. Putting deferred scripts first is a really bad idea. Example 2
Re: [whatwg] defer on style, depends
Garrett Smith wrote: Because you have scripts after your stylesheets, not just stylesheets. Really, controlled experiments are hard. You have to hold all but one variable constant. OK, I modified the example: http://localhost/jstest/block/link-img-noscript.html The bottom script will not load ('load' as opposed to 'run') in Firefox/3.0.6 until after 5 seconds. Right. Because you still have another script before it. The result shows that example.js loads 5 seconds after the initial page load. example.js waits for the stylesheet to load. It waits for the first script to execute, which waits for the stylesheet to load. That's not quite the same thing. My concern is with the recomputation you mentioned. Can you elaborate on that, or point me to a webpage that explains it? Well, once a new stylesheet loads you have to redo rule matching for all nodes that might be affected in the document. In practice, I believe current UAs will rerun the rule matching algorithm on all nodes in the document. Question: What does IE do? That's a really good question. I don't have IE on hand to test with; do you? Well, one option is to stop worrying about micromanaging the load order and assume that speculative parsing will solve your problems will it? Possibly. If the author could declare what a script depends on and let the implementation determine what to load and when, would that be too complicated? Too complicated for whom? The author or the implementation? -Boris
Re: [whatwg] defer on style, depends
Ian Hickson wrote: On Fri, 13 Feb 2009, Boris Zbarsky wrote: The current Gecko behavior is that any stylesheet load started by parsing a style or link tag will increment a counter on the document (well, on a per-document script loader object, to be more precise). Completion of the load will decrement the counter. While the counter is nonzero, script execution is blocked. When it goes back to 0, the first pending script (if any) is run. If this increments the counter again, no more scripts are run until the count goes to 0 again. So it doesn't matter how the script is created/inserted, but the only stylesheets that block scripts are ones that the parser knows about. So only the ones present in the original source or added via document.write. If you createElement a link and insert it into the DOM, it won't block script execution. Also, link elements pointing to alternate style sheets don't block script execution. So in this: !DOCTYPE html ... script document.write('link rel=stylesheet href=style'); document.write('scripta();\/script'); b(); /script ...is the script paused after the second document.write() call, before a() and b() execute? No. What's paused is execution of new scripts, not of existing ones. So in this case, b() executes immediately, while a() executes after the stylesheet loads. Here's a simple testcase to demonstrate that: !DOCTYPE html script var res = ; document.write('link rel=stylesheet href=data:text/css,'); document.write('scriptres+=a\/script'); res+=b; /script body onload=alert(res)/body I realize that this does mean that the execution order of a() and b() is different if the link is written out as above -Boris
Re: [whatwg] defer on style, depends
On Sun, Feb 15, 2009 at 9:54 AM, Boris Zbarsky bzbar...@mit.edu wrote: Garrett Smith wrote: Because you have scripts after your stylesheets, not just stylesheets. Really, controlled experiments are hard. You have to hold all but one variable constant. OK, I modified the example: http://localhost/jstest/block/link-img-noscript.html The bottom script will not load ('load' as opposed to 'run') in Firefox/3.0.6 until after 5 seconds. Right. Because you still have another script before it. Yes, you are correct. It is the script that blocks the external script from being requested; not the stylesheet. This has been changed in 3.1pre. The result shows that example.js loads 5 seconds after the initial page load. example.js waits for the stylesheet to load. It waits for the first script to execute, which waits for the stylesheet to load. That's not quite the same thing. Yes, thank you. My concern is with the recomputation you mentioned. Can you elaborate on that, or point me to a webpage that explains it? Well, once a new stylesheet loads you have to redo rule matching for all nodes that might be affected in the document. In practice, I believe current UAs will rerun the rule matching algorithm on all nodes in the document. I can see why rule matching would happen for all nodes in the document. On what occasion(s) do(es) that algorithm run? Aside: Could the CSS have a selector applied to it for sub-matches? e.g. First find nodes in the document that match a selector value, then match stylesheets rules that match the subset. So instead of: .infoPanel table { } .infoPanel table tr { } it would be (pseudocode): .infoPanel { table {} tr {} } Could such a strategy for rule-matching help performance, or would it hinder performance or be too much work to maintain? I know it is off topic, but the effect of rule matching would hurt performance. Question: What does IE do? That's a really good question. I don't have IE on hand to test with; do you? LOL. No, I have only my mac at home. I need a new laptop with windows. Does anyone reading have windows? Well, one option is to stop worrying about micromanaging the load order and assume that speculative parsing will solve your problems will it? Possibly. If the author could declare what a script depends on and let the implementation determine what to load and when, would that be too complicated? Too complicated for whom? The author or the implementation? I see a few edge cases. For example: A script depends on something that is never loaded. A script depends on something that is added to the document later. A script depends on an alternate stylesheet. Reading script depends=a.../script seems clear to me. Then again, I stole the idea from ANT. For the implementation, I do not actually know because I have not worked on that code. What are your thoughts? -Boris Garrett
Re: [whatwg] defer on style, depends
Garrett Smith wrote: I can see why rule matching would happen for all nodes in the document. On what occasion(s) do(es) that algorithm run? Depends on the UA, probably. For Gecko in particular, any time a stylesheet is added to or removed from the document, any time a rule is added to or removed from a stylesheet via the CSSOM, and any time a rule is changed via the CSSOM. The one exception is inline style; changing that only performs style recomputation (which includes selector matching) on the subtree rooted at the node whose inline style has changed. In general, the whole setup in Gecko is optimized around changes to nodes being common and changes to stylesheets being rare. So far this is a good working assumption; if that ever changes we'll look into optimizing changes to stylesheets more. Could such a strategy for rule-matching help performance, or would it hinder performance or be too much work to maintain? To a first approximation it'd have no effect on performance. Too complicated for whom? The author or the implementation? For the implementation, I do not actually know because I have not worked on that code. What are your thoughts? I haven't thought about this enough to have any useful ones yet. -Boris