<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>getiblog &#187; labjs</title>
	<atom:link href="http://blog.getify.com/tag/labjs/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.getify.com</link>
	<description>javascript, performance, and ui musings</description>
	<lastBuildDate>Thu, 15 Dec 2011 17:37:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>On Script Loaders</title>
		<link>http://blog.getify.com/on-script-loaders/</link>
		<comments>http://blog.getify.com/on-script-loaders/#comments</comments>
		<pubDate>Thu, 16 Dec 2010 20:36:13 +0000</pubDate>
		<dc:creator>getify</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Performance Optimization]]></category>
		<category><![CDATA[browsers]]></category>
		<category><![CDATA[ControlJS]]></category>
		<category><![CDATA[HeadJS]]></category>
		<category><![CDATA[labjs]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[script loader]]></category>
		<category><![CDATA[standards]]></category>

		<guid isPermaLink="false">http://blog.getify.com/?p=739</guid>
		<description><![CDATA[Comment Two recent projects have come out that attempt to address the &#8220;dynamic script loader&#8221; use case: HeadJS and ControlJS. Since I&#8217;m the creator of LABjs, a general, all-purpose, performance-oriented dynamic script loader that&#8217;s been around for about a year and a half now, and is well-known enough to be in use on several major [...]]]></description>
			<content:encoded><![CDATA[<h3>Comment</h3>
<p>Two recent projects have come out that attempt to address the &#8220;dynamic script loader&#8221; use case: <a href="http://headjs.com/" rel="nofollow">HeadJS</a> and <a href="http://stevesouders.com/controljs/" rel="nofollow">ControlJS</a>. Since I&#8217;m the creator of <a href="http://labjs.com">LABjs</a>, a general, all-purpose, performance-oriented dynamic script loader that&#8217;s been around for about a year and a half now, and is well-known enough to be in use on several major sites, including <a href="http://twitter.com">Twitter</a>, <a href="http://vimeo.com">Vimeo</a>, and <a href="http://zappos.com">Zappos</a>, many people ask my opinions when new entries into this space arise.</p>
<p>I&#8217;ve been hesitant to rush to negative judgement on either one, because I believe it&#8217;s important to encourage experimentation and progress in this area, for the sake of the greater web. But I do think it&#8217;s important to shed a little bit of light onto both projects and explain some concerns I have with their approach. I respect the authors of both libraries, so I hope they will take my ramblings here as constructive criticism rather than an attack.</p>
<h3>ControlJS: backstory</h3>
<p>ControlJS comes from the immensely experienced and talented <a href="http://stevesouders.com">Steve Souders</a>, who leads performance efforts for Google. For readers who aren&#8217;t aware, when I first was building LABjs back in 2009, Steve stepped in and offered some very helpful and timely advice and collaboration, and I credit much of LABjs&#8217; success since to Steve&#8217;s wisdom and experience.</p>
<p>Recently, though, Steve has focused in a different direction than was necessarily the focus back then. His focus is now more aimed at delaying all script loadings until after the rest of the page content has loaded, whereas LABjs&#8217; goal was to simply allow easy parallel loading of scripts (instead of blocking behavior) right along side the rest of the page content. In my opinion, there are some scripts which are less important, like Google Analytics, social sharing buttons, etc. And I whole heartedly agree with &#8220;deferring&#8221; that code&#8217;s loading until &#8220;later&#8221;, to not take up precious valuable bandwidth/connections/cpu.</p>
<p>But there&#8217;s also a lot of JavaScript that is just as important as the content it decorates, and to me, the idea of delaying that code by a noticeable amount will lead, in general, to proliferation of a distasteful visual effect I call <strong>&#8220;FUBC&#8221; (Flash of Un-Behaviored Content)</strong>. In other words, we&#8217;ll see pages that flash up raw text content, only to swap out a moment or two later into the widgetized and JavaScript stylized version of the page, where the content is in fancy tab-sets, modal dialogs, etc. </p>
<p>To be clear, any dynamic script loader can create this effect unintentionally, including LABjs. But what ControlJS appears to be intentionally doing is delaying scripts even longer past when content is visible/useable, which will exacerbate this FUBC problem quite a bit.</p>
<p>There are of course ways to mitigate this, using default/inline CSS rules and &lt;noscript> tags (a technique I talk about on the LABjs site), but if you hide all the raw content with CSS and don&#8217;t re-display it until the JavaScript is present, you lose <strong><em>ALL</em></strong> of the benefit of deferring that JavaScript logic to let the content load quicker. The goal is admirable, but I think it will end up being neutral or worse UX for most sites.</p>
<p>This is a tenuous and difficult UX balance that sites need to consider carefully. I do not endorse Steve&#8217;s suggestions, that basically all sites should move to this model. It makes sense for some of them, if they intentionally design their UX that way. But it&#8217;s by far not optimal for a lot of sites, and using his suggestions will trade out performance for really sub-optimal user experience during page-load if not done with caution and reserve.</p>
<p>So, that is the context under which Steve presents us ControlJS. It&#8217;s an attempt to create a script loader that more closely models his view of how page-loads should work (that scripts should all defer loading and execution until all content is finished). If you agree with him, and aren&#8217;t worried about FUBC (or have already carefully thought about and designed around it), ControlJS is something to at least consider. But if you&#8217;re just planning to drop in ControlJS to an existing site, I think this is possibly a <em>big</em> mistake and the wrong direction for the web to head in.</p>
<p>So, I simply chose to disagree with Steve on this point, and we&#8217;re now focusing on different goals.</p>
<h3>ControlJS: approach</h3>
<p>In addition to my UX concerns with Steve&#8217;s approach to page-load optimization that&#8217;s embodied in ControlJS, I have some problems with the functional approach he&#8217;s taken as well.</p>
<h4>User-agent</h4>
<p>First, ControlJS relies on browser user-agent sniffing to choose different loading techniques for different browsers. I have been a very vocal critic of user-agent sniffing, even to the <a href="http://www.nczonline.net/blog/2010/01/12/history-of-the-user-agent-string/">opposition</a> of brilliant guys like <a href="http://twitter.com/slicknet">Nicholas Zakas</a>.</p>
<p>I&#8217;m not going to rehash the whole debate of user-agent sniffing. I simply won&#8217;t use it, and I think most people agree that it&#8217;s a bad choice. Feature-detection is far preferable. In between the two, but I still think better than user-agent sniffing by an important amount, is <strong>browser-inferences</strong>. LABjs uses a couple of browser-inferences (basically, testing for a feature known to be characteristic of only one or a family of browsers), <strong>very reluctantly</strong> as a temporary stop-gap until such a time as the browsers support dynamic script loading use-cases with feature-testable functionality. ControlJS makes no such attempt to be robust or future-thinking on this topic, simply relying on basic user-agent sniffing. This definitely worries me.</p>
<p>Moreover, I&#8217;ve been heavily engaged in trying to petition browsers and the W3C to support native functionality that supports the dynamic script loading use-cases, in a <strong>feature-testable</strong> way. If you&#8217;re unfamiliar with that proposal/effort, take a look at this WHATWG Wiki Page: <a href="http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order">Dynamic Script Execution Order</a>.</p>
<p>Mozilla (starting with FF 4b8, due out in a few days) and Webkit (very shortly in their Nightlies) have implemented the `async=false` proposal made there, and done so in a way that&#8217;s feature testable. LABjs 1.0.4 was released a few weeks ago with the new feature-test in it to take advantage of that new functionality when browsers implement it. Eventually, the goal is to deprecate and remove the old hacky browser inferences (and the old hacky browser behavior it activated) in favor of this new (and hopefully soon standardized) behavior.</p>
<p>I asked Steve several times to join in the efforts to advocate for this new feature-testable native functionality to be standardized and adopted by browsers, which I believe will <strong>DRASTICALLY</strong> improve script-loaders&#8217; ability to performantly load scripts into pages. He politely <em>declined</em> to participate, and suggested my efforts were misguided. And instead, he released ControlJS using old and sub-optimal user-agent sniffing in its place. This is obviously not how I hoped things would progress.</p>
<h4>Preloading</h4>
<p>During the development of the original 1.0 release of LABjs back in 2009, I consulted several times with Steve on various trade-offs that had to be made to get a generalized script loader to address all the various use-cases. </p>
<p>The biggest problem I faced was that some browsers (namely IE and Webkit) offered no direct/reliable way to load scripts in parallel but have them execute in order, which is important if you have dependencies (like jQuery, jQuery-UI, and plugins, etc). This is especially difficult to do if you are loading any or all of those scripts from a remote domain (like a CDN), which is of course quite prevalent on the web these days.</p>
<p>I developed and tested a trick I call &#8220;cache-preloading&#8221; (something which is now getting a lot of attention from various script loaders), which was basically a way to handle this. It was openly admitted to be a hack, sub-optimal, and hopefully something that would be eventually removed from LABjs. </p>
<p>There are various ways to approach this trick, but the fundamental characteristic is that you &#8220;preload&#8221; a bunch of scripts into the browser cache <strong>without execution</strong>, and then you make a second round of requests for those scripts, pulling them from cache, to then execute them. The reason this trick is important to consider is that it has a rather large (and potentially fatal) assumption attached to it: <strong>that all the scripts being requested are served with proper and future expiration headers</strong>, so that they can actually be cached.</p>
<p>Importantly to this post, relying on this assumption was very worrisome to Steve in our discussions back then. He asserted that as much as <del>70%</del> <strong>(Update: maybe 38%, 51%, &#8230;)</strong> of script resources on the internet are not sent with proper caching headers (or none at all), and so for all of those scripts, if they are loaded with a script loader using a &#8220;preloading&#8221; trick, the first load won&#8217;t successfully cache, and the second request will cause a second full load. Not only is that terrible for performance, depending on the script loader&#8217;s internal logic, this assumption failing can create hazardous race conditions.</p>
<p>In addition to the possible double-load, Steve was also worried that even if a script was properly cached, the delay for the second cache hit could be noticeable and bad for large scripts. Again, large script files are very common these days, with the proliferation of advice from people like Steve who suggest concatenating all files into one file (to reduce HTTP requests).</p>
<p>After much discussion and back-and-forth, I reluctantly decided that Steve&#8217;s concerns were valid, and so I added more complexity to LABjs (increasing its size and introducing several ugly hacks) to try to abate this problem. We tenuously agreed that the likelihood was that most of the scripts that are being served with improper headers are being self-hosted (thus on local domains), and that remote domains (like CDNs) would be much more likely to be correctly configured.</p>
<p>I devised a solution where LABjs uses XHR to &#8220;preload&#8221; local scripts, and only falls back to the &#8220;cache-preload&#8221; trick for remote scripts. In addition, I gave people the ability, through config values in the LABjs API, to easily (with a single boolean value) turn off either or both of those preloading tricks, so that developers would be much less likely to accidentally trip over this problem if they indeed had to load a script that had improper caching behavior.</p>
<p>I&#8217;m sure you can imagine my surprise when, this morning, I cracked open Steve&#8217;s code, and I see that he&#8217;s now using the &#8220;cache-preloading&#8221; tricks as the <em>only</em> method, without XHR. In other words, he was really concerned about this problem when he helped me design (and complicate LABjs), but now it&#8217;s not a concern of his. He briefly mentions the assumption of cacheability off-handedly in his blog post, buried in a lot of other text.</p>
<p>I haven&#8217;t seen any research to suggest a radical shift since late 2009 that has most or all script resources now being properly cacheable. So I still consider the concerns that Steve voiced to be quite real and important.</p>
<p>Again, I always considered the &#8220;cache-preload&#8221; to be a hacky last-ditch fallback, and always have intended to remove it as soon as browsers provided a better solution (that&#8217;s happening now, slowly but surely). So, I&#8217;m <strong>quite concerned</strong> to say the least that ControlJS (and HeadJS and others) are latching onto the &#8220;cache-preload&#8221; as their primary (or only) means of handling parallel-load-serial-execute. </p>
<p>Not only are they white-washing over the cacheability assumption, They&#8217;re completely ignoring the recent movement by Mozilla and Webkit to implement the far-preferable `async=false` functionality. I consider this quite unfortunate.</p>
<h4>Brittle Cache-Preloading</h4>
<p>One last note on the &#8220;cache-preload&#8221; tricks: LABjs&#8217; version of the &#8220;cache-preload&#8221; trick was to use a non-standard and undocumented behavior of certain browsers (IE and Webkit) that would fetch a script resource into cache, but not execute it, if the script element&#8217;s `type` value was something fake like &#8220;script/cache&#8221; (instead of &#8220;text/javascript&#8221;).</p>
<p>However, the HTML spec <em>now</em> says that such resources should NOT be fetched. So, Webkit (about a month or two ago) dutifully obeyed the spec and patched their browser to stop fetching them. This means that LABjs&#8217; &#8220;cache-preload&#8221; trick broke entirely in Webkit nightlies. Now, thankfully, Webkit is moving rapidly to adopt the more preferred `async=false` in its place, so hopefully LABjs won&#8217;t be broken in any major Webkit-based browser release.</p>
<p>But there&#8217;s a <em><strong>SUPER IMPORTANT</strong></em> lesson that must be learned here. LABjs got by with non-standard behavior for awhile. But browsers are <em>quickly</em> catching up to the spec/standards. It was almost disastrous for LABjs, had `async=false` not gotten the attention it did, to die a public death because of relying on hacky non-standard behavior.</p>
<p>But ControlJS, HeadJS, and many other script loaders like them are doing the same thing. They aren&#8217;t necessarily using the exact same trick as LABjs used, but they are pinning their entire loading functionality on hacky, non-standard behavior. ControlJS uses the <a href="http://www.phpied.com/preload-then-execute/">&lt;object> preloading hack</a> for some browsers and the `new Image()` hack for other browsers. </p>
<p>Essentially, they&#8217;re relying on the fact that these browsers will fetch the script resource content into cache but not execute it because the container used to do the fetching doesn&#8217;t understand JavaScript. I don&#8217;t know about you, but this sounds to me dangerously like the spec statement of telling browsers not to fetch content with a declared MIME-type the browser can&#8217;t interpret. How long do you think it&#8217;ll be before Webkit, Mozilla, Opera, or IE patch to stop fetching/caching content via &lt;object> or `Image()` that they can&#8217;t interpret?</p>
<p>Some have argued that &lt;object> and `Image()` will always have to fetch such content, because the browser can&#8217;t know the URL won&#8217;t return valid image or object content until after it receives the response. This may be true, the browser may always have to fetch it. <strong>But the browser might chose to discard the contents (and not cache it)</strong> if it sees a content-type that it won&#8217;t consider valid for the requesting container. If I were on a browser dev team, and were coding with the intent of following the spirit of the spec, that&#8217;s exactly the logic I&#8217;d implement.</p>
<p>And I&#8217;d especially do that, even though it may break script loaders, because the spec process (and browsers) are already starting to implement a more direct and reliable approach: `async=false`.</p>
<h4>DOM-ready</h4>
<blockquote><p>
I think itâ€™s ironic that JavaScript modules for loading scripts asynchronously have to be loaded in a blocking manner. From the beginning I wanted to make sure that ControlJS itself could be loaded asynchronously.
</p></blockquote>
<p>I understand and empathize completely with Steve&#8217;s sentiment here. He and I both agreed from day one of LABjs that it&#8217;s unfortunate that you have to &#8220;load some JavaScript so that you can load more JavaScript&#8221;. But at its heart, this is how bootstrapping works, and it&#8217;s a reality.</p>
<p>However, I believe Steve has completely glossed over a really important point (and it kind of ties back to my earlier section on the UX of FUBC): if you asynchronously and dynamically load the loader, and don&#8217;t take special precautions, the loader has no way of knowing (in some browsers, including FF3.5 and before) if the page&#8217;s DOMContentLoaded (aka &#8220;DOM-ready&#8221;) has passed or not.</p>
<p>While the script loader doesn&#8217;t really need to care to much about DOMContentLoaded, some of the scripts that you may be loading do very much care. As I wrote about last year regarding <a href="http://blog.getify.com/2009/11/why-dom-ready-still-sucks/">jQuery, DOM-ready, and dynamic script loading</a>, it&#8217;s very common that people write jQuery code that looks like this:</p>
<pre class="code">
$(document).ready(function(){
   // I know the DOMContentLoaded/DOM-ready event has passed! wee!
});
</pre>
<p>The problem is, jQuery can&#8217;t reliably detect DOMContentLoaded in FF3.5 and before (and a few other obscure browsers) <strong>if</strong> jQuery itself is not loaded statically/synchronously (that is, in a blocking way, so that it&#8217;s loaded before DOMContentLoaded can pass). So, if you just blindly load jQuery dynamically, and it happens to finish loading after DOMContentLoaded/DOM-ready has passed, any code you have in your page that looks like that snippet above will just sit forever waiting, and never fire!</p>
<p>So, LABjs takes advantage of the fact that you are almost certainly going to load &#8220;LAB.js&#8221; file with a normal blocking script tag (I know, counter-intuitive, right!?). Inside of LAB.js, at the very end, is a small little snippet that detects if the page doesn&#8217;t properly have a `document.readyState` property on it (what jQuery uses for detecting DOMContentLoaded in those browsers), and if so, it patches the <em>page</em>.</p>
<p>This has the effect that a few hundred milliseconds later, when jQuery finishes loading (if you&#8217;re using jQuery of course!), even if DOMContentLoaded has already passed, jQuery will properly see the right state, and your code will fire immediately. The page-level hack looks like this:</p>
<pre class="code">

// required: shim for FF <= 3.5 not having document.readyState
if (document.readyState == null &#038;&#038; document.addEventListener) {
    document.readyState = "loading";
    document.addEventListener("DOMContentLoaded", handler = function () {
        document.removeEventListener("DOMContentLoaded", handler, false);
        document.readyState = "complete";
    }, false);
}
</pre>
<p>This is an unfortunate page-level hack that's necessary for FF3.5 and before, for jQuery to be properly loaded dynamically and still have code like that snippet above operate as expected. You can see the code is pretty small and compact, so including it in LABjs doesn't hurt the size/complexity too much. But it works <em>because LABjs typically is loaded statically</em>.</p>
<p>So, does that mean LABjs can't be loaded dynamically and still have jQuery and DOM-ready code work? <strong>No!</strong> It just means that the page-level hack in that snippet needs to be part of whatever little "bootstrapper" code you use to dynamically load LABjs to a page. And it means that THAT code that you use as a bootstrapper for LABjs must itself load statically (like in an inline script-block, etc).</p>
<p>In fact, I advocated a little while back exactly how to dynamically load LABjs and still preserve this whole DOM-ready business with <a href="https://gist.github.com/603980">this snippet</a>.</p>
<p>What concerns me about ControlJS, HeadJS, and almost every other loader out there is that they completely ignore this important point about DOMContentLoaded detection for FF3.5 and below. I know for me, I still regularly use LABjs to dynamically load jQuery, and I still use `$(document).ready(...)` to safely wrap code, and I still support FF3.5. So for me, this DOM-ready protection code is important. Whether it appears in the loader code itself, or in the snippet of bootstrapper code, I think those loaders are really missing something important if they don't include that snippet (or something like it).</p>
<h4>Invalid Markup</h4>
<p>This post is already getting really long (again! I can't be short-spoken even if I try!). So I'm going to at least keep this final section brief, and try to wrap up quickly.</p>
<p>ControlJS is able to achieve its "deferral" of script loading and execution (until after window.onload in fact!) by suggesting that you must change all your script elements in your code to be unrecognizable by the browser loading mechanism.</p>
<p>You change a script tag's `src` attribute to be `cjssrc` instead. This is an invalid attribute name, and will be ignored by the browser. <strong>But it also invalidates your markup.</strong> I consider this to be a bad-practice. At least the attribute could have been `data-src` or something, so that it fits with valid spec attribute naming.</p>
<p>Secondly, ControlJS requires that you change a script block's `type` value to "text/cjs" (from "text/javascript"). I have two problems with this approach. Firstly, as we discussed above, the spec and standards bodies are moving to explicitly de-supporting invalid types. What if sometime soon, the spec says that any element with an unrecognized type should not even be added to the DOM but should be entirely ignored? </p>
<p>Or what if some browser just interprets what the spec currently says to mean that? If I were a browser developer, I could easily argue that the ignoring of such an element (not adding it to the actual DOM) would help improve the page's performance by taking up less memory and having fewer DOM nodes to inspect during DOM traversal/manipulation.</p>
<p>Also, he chose "text/cjs". This assumes future-wise that no MIME-type will ever take the name "text/cjs". Notice that LABjs at least chose a much different value, like "script/cache", which is far less likely to have future collisions. But Steve chose a "text/xxxx" format for the value, which fits closely with how such values currently are assigned, but also makes it more likely that there will be a conflict someday. </p>
<p>Moreover, in HTML5, the type value is now optional, and for performance reasons, I (and most people) now omit that from our markup. ControlJS will require us to go back and add `type` attributes to all our script tags, making the markup <em>slightly</em> larger. That's pretty minor, but it bugs me nonetheless.</p>
<p>Lastly, it is unclear from the code or the documentation what the expected/suggested behavior should be if I have some script tag elements in my markup that are marked-up to have CJS bindings, and other script tags that I leave alone. How will CJS loaded scripts interact (before or after) scripts that are loaded using the browser's native mechanism? If there's some reason I need to have a mixture of CJS and non-CJS script tags in my page, it will make the interpretation of my markup (specifically, the implied execution order of the script elements) a <em>lot</em> more confusing.</p>
<h4>Summary</h4>
<p>This is part 1 of this post. I'm going to make another post soon (part 2) where I shift my focus from ControlJS to HeadJS (and possibly other script loaders).</p>
<p><strong>Again, I apologize to Steve (and to anyone else)</strong> if the tone of this post seems to be overly harsh. But I think it's important that the other side of the coin be put out there for developers to consider as they compare how ControlJS differs from something like LABjs.</p>
<p>Moreover, I reiterate what I've said a dozen times already: <strong>instead of creating more and different script loaders, I think a better use of our time would be to consolidate efforts in getting the browsers and the spec/W3C to give us a reliable native mechanism for managing dynamic script loading.</strong> Since `async=false` is already moving along nicely, I encourage and invite anyone who's interested to join that discussion.</p>
<p>I hope very soon that proper and simple handling of dynamic script loading will be very easy and straightforward, and well-conforming script loaders (which I can say LABjs will certainly be) will eventually be free from a lot of hacky, legacy junk that weighs them down. I call on all other script loaders to join that effort for a better script loading future. (ok, yeah, that was lame. <img src='http://getiblog.2static.it/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> )</p>
<div><a class="addthis_button" href="//addthis.com/bookmark.php?v=250" addthis:url='http://blog.getify.com/on-script-loaders/' addthis:title='On Script Loaders '><img src="//cache.addthis.com/cachefly/static/btn/v2/lg-share-en.gif" width="125" height="16" alt="Bookmark and Share" style="border:0"/></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.getify.com/on-script-loaders/feed/</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
		<item>
		<title>LABjs and W3C&#8230; brief update</title>
		<link>http://blog.getify.com/labjs-w3c-brief-update/</link>
		<comments>http://blog.getify.com/labjs-w3c-brief-update/#comments</comments>
		<pubDate>Mon, 25 Oct 2010 18:29:04 +0000</pubDate>
		<dc:creator>getify</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Misc]]></category>
		<category><![CDATA[Performance Optimization]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[labjs]]></category>
		<category><![CDATA[mozilla]]></category>
		<category><![CDATA[spec]]></category>
		<category><![CDATA[w3c]]></category>
		<category><![CDATA[webkit]]></category>

		<guid isPermaLink="false">http://blog.getify.com/?p=612</guid>
		<description><![CDATA[Just wanted to post a quick update to the ongoing discussion on where things currently stand with LABjs and the breaking changes in Mozilla and Webkit trunks precipitated by some incomplete wording in W3C spec. A really long thread on W3C public-html list has been brewing over the past few weeks regarding the fact that [...]]]></description>
			<content:encoded><![CDATA[<p>Just wanted to post a quick update to <a href="http://blog.getify.com/2010/10/mozilla-labjs-part-2/">the ongoing discussion</a> on where things currently stand with LABjs and the breaking changes in Mozilla and Webkit trunks precipitated by some incomplete wording in W3C spec.</p>
<p>A <a href="http://lists.w3.org/Archives/Public/public-html/2010Oct/0377.html">really long thread on W3C public-html list</a> has been brewing over the past few weeks regarding the fact that the W3C spec does not adequately provide a way for web authors to handle the use-case of parallel-load/execute-in-order, which is important for dynamic script loaders (like LABjs).</p>
<h3>Other options</h3>
<p>A variety of different view points and alternative ways to address the issue have been thrown around. Some of the people on the list feel that this use case is not important to solve because authors can just concat all their scripts together. This is obviously short-sighted given many previous discussions that demonstrate the performance benefits of parallel loading and independent caching.</p>
<p>Other members on this list feel the best way to handle the use-case is to create some sort of API for authors to directly do the &#8220;preloading&#8221; trick. This trick essentially relies on loading all scripts in parallel into the cache but <strong>not</strong> executing them (using several possible tricks), and then once they&#8217;re all in cache, re-requesting them with proper &lt;script> nodes to immediately pull them from cache and execute them.</p>
<p>The fact that LABjs invented this trick (using the fake mime-type &lt;script type=&#8217;script/cache&#8217;>) for IE, Webkit, and Chrome browsers does not mean I think it&#8217;s the best way &#8212; in fact, it&#8217;s an ugly and error-prone approach to the use-case, and I always hoped I could eventually deprecate that once the spec reflected a better solution.</p>
<p>One major gotcha to &#8220;preloading&#8221; is that if any resource in the &#8220;preloading&#8221; queue doesn&#8217;t send out proper caching headers, not only will that resource end up being requested twice, but the assumption of immediate execution from cache will fail and thus dependencies will be in a race condition. Some estimates have suggested that as much as 70% of all script resources on the web are served without proper caching headers &#8212; a scary number in its own right, but also quite illustrative of the pitfall to this technique.</p>
<p>So, the part of the crowd that thinks the solution lies in &lt;link rel=prefetch>, or `new Image().src=&#8230;`, or <a href="http://www.phpied.com/preload-then-execute/">Stoyan Stefanov&#8217;s &lt;object> preloading technique</a>, or&#8230; those options are all, in my opinion, missing the bigger picture of how &#8220;preloading&#8221; can really fall over for this use-case if caching is not correct. Moreover, they are all more complicated to implement, which makes script loaders like LABjs more complicated than they should have to be.</p>
<h3>The Proposal</h3>
<p>So, Henri (from Mozilla) and I have been discussing a simple proposal to amend the W3C spec to cover the use case in a straightforward way that avoids such clumsiness and pitfalls.</p>
<p>In a nutshell, the idea is to extend the spec so that the `async` property is present and its value (true/false) is respected, both for &lt;script> tags in the HMTL markup and for script-elements that are injected dynamically (currently, the spec says nothing about `async` for injected elements). If an author (like the LABjs tool) wanted to inject scripts to have them load in parallel, but have their order preserved, they could simply set `async=false`. If the author instead wanted the &#8220;execute as soon as possible&#8221; behavior because there were no dependencies in the queue of loading scripts, they could set `async=true`.</p>
<p>Ultimately, this actually makes the spec more consistent and symmetrical, given that we&#8217;re making `async` work pretty much the same for injected script elements as it already does for markup &lt;script tags.</p>
<p>This proposal idea is still forming, but that&#8217;s the main idea. Several people on the list have suggested support for the idea. Others however are not in favor of it, and they are the main voices suggesting myriad other more complex solutions (like a `document.executeScripts` API, for instance). </p>
<p>So, the discussion definitely needs to continue and find some consensus. Then, we need to advocate for W3C to adopt it, and then we need to really rally to get all the browsers (especially Webkit and IE) to agree to implement the spec. All of that needs to happen before the next major release of Webkit or FF, or LABjs is going to basically fail.</p>
<p>As you can see, we&#8217;re far from out of the woods yet. I call on you the community to help join the effort. The more people we can get behind a proposal, the more of a chance that something might happen before the inevitable bulldozer of &#8220;progress&#8221; demolishes what LABjs tried to build.</p>
<h3>Next Steps</h3>
<p>Because the aforementioned email thread is now quite long and complicated to digest, I am going to be moving the discussion over to a simple Wiki page in WHATWG. I encourage you to try and read some of the recent (dozen or so, probably) messages on that email thread to get up to speed, and then join the effort in continuing the discussion toward consensus over on the Wiki. I will post an update here as soon as that page is up.</p>
<h4>Update</h4>
<p>Here&#8217;s the <a href="http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order">Wiki page on WHATWG</a> to continue the discussion.</p>
<div><a class="addthis_button" href="//addthis.com/bookmark.php?v=250" addthis:url='http://blog.getify.com/labjs-w3c-brief-update/' addthis:title='LABjs and W3C&#8230; brief update '><img src="//cache.addthis.com/cachefly/static/btn/v2/lg-share-en.gif" width="125" height="16" alt="Bookmark and Share" style="border:0"/></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.getify.com/labjs-w3c-brief-update/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mozilla &amp; LABjs&#8230; part 2</title>
		<link>http://blog.getify.com/mozilla-labjs-part-2/</link>
		<comments>http://blog.getify.com/mozilla-labjs-part-2/#comments</comments>
		<pubDate>Thu, 07 Oct 2010 17:12:49 +0000</pubDate>
		<dc:creator>getify</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Performance Optimization]]></category>
		<category><![CDATA[FF4]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[labjs]]></category>
		<category><![CDATA[loading]]></category>
		<category><![CDATA[mozilla]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[order]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[script loader]]></category>

		<guid isPermaLink="false">http://blog.getify.com/?p=591</guid>
		<description><![CDATA[This post is the immediate &#8220;part 2&#8243; follow-up to Mozilla &#38; LABjs: the story unfolds. Definitely read that before proceeding to read here. As I mentioned at the beginning of that previous post, I am writing to address the points raised in the comment by the Mozilla developer who was responsible for the change in [...]]]></description>
			<content:encoded><![CDATA[<p>This post is the immediate &#8220;part 2&#8243; follow-up to <a href="http://blog.getify.com/2010/10/mozilla-labjs-the-story-unfolds/">Mozilla &amp; LABjs: the story unfolds</a>. Definitely read that before proceeding to read here.</p>
<p>As I mentioned at the beginning of that previous post, I am writing to address the points raised in the <a href="http://blog.getify.com/2010/10/ff4-script-loaders-and-order-preservation/comment-page-1/#comment-748">comment by the Mozilla developer</a> who was responsible for the change in script-load-order behavior. I already responded in part 1 to the overal condescending (in my opinion) tone of that comment, but here I will address very specific points made.</p>
<h3>Dive in</h3>
<blockquote><p>That&#8217;s not a safe data point to draw forward-looking expectations from. IE and WebKit haven&#8217;t executed script-inserted external scripts in insertion order. When two browsers do one thing and two other do another thing, it should be no surprise to anyone that when standardization happens, at least two browsers need to change their behavior to comply.</p>
<p>I can&#8217;t stress this enough: When you see that one set of browsers do one thing on a given point and another set of browsers does something else on the same point, you shouldn&#8217;t assume that these two sets of browser will retain differing behaviors forever.</p>
<p>When you see one set of browsers doing one thing and another doing another, UA sniffing (LABjs doesn&#8217;t sniff the UA string but it sniffs &#8220;Gecko&#8221; from the presence of MozAppearance) is exactly the wrong thing to do.</p></blockquote>
<p>I addressed this point in the <a href="http://blog.getify.com/2010/10/mozilla-labjs-the-story-unfolds/">previous post</a>, but let me reiterate: It&#8217;s not my fault the browsers have carelessly left these doors wide open. I was not content to sit on the sidelines and wait for years while web performance optimization remained impossible to grasp. So I jumped into the fray and solved the use case based on what we have now.</p>
<p>I&#8217;m not so naive as to believe the landscape of browsers and features will never change. That&#8217;s not the point of my complaint. <strong>The whole point of my complaint with Mozilla (and with ill-conceived/short-sighted standards you&#8217;re falling back on) is that if you&#8217;re going to change behavior, you have to engage the community actively, especially the community that&#8217;s most affected.</strong></p>
<p>LABjs is, I think fair to say, pretty well known at this point, and it&#8217;s not unreasonable to think that Mozilla could have done some google searches to see if there were any well-known or widely-used tools that may be affected by the change. Certainly LABjs would have come up somewhere in the first page or two of some of those searches.</p>
<p>I fully expect browsers to change and get better, but what <em>must</em> also happen is that the browsers must engage the community to see what the needs are. Mozilla has a <strong>GREAT TRACK RECORD</strong> in the community of this in the past. But the handling of this particular issue, I think was not up to that same &#8220;standard&#8221;.</p>
<p>What I would have hoped for, and what I hope for still, is that Mozilla will proactively try to address the valid and already existent use cases when they make a change to behavior. If you can&#8217;t support the behavior any more, give us a way to definitively detect the change (so we can still support backwards in your browser family) and also give us some alternative that still serves the use-case. Callously claiming that the use case is not valid (or even &#8220;may not be&#8221;) is not a way to endear you to the members of the community.</p>
<blockquote><p>The right thing to do is to do something that works without browser sniffing in all current browsers. For cross-origin script library loads this means designing the script libraries in such a way that the act of evaluating a given library doesn&#8217;t cause the library to call into another library but only makes the API of the script available such that only calling the API potentially causes a cross-library call. (Yes, I&#8217;m saying that in the current environment, that LABjs probably shouldn&#8217;t have tried to provide cross-origin ordered loading of external scripts given that it couldn&#8217;t be provided without either UA-sniffing or making dangerous assumptions about the caching relationship of loads initiated by object/img elements and loads initiated by script elements.)</p></blockquote>
<p>This is an absurd assertion to make. I don&#8217;t consider it a valid option to just say LABjs should never have happened because the browsers and standards didn&#8217;t have a solution. Would you say the same thing to Steve&#8217;s face: &#8220;Steve&#8230; stop trying to improve the web performance optimization of scripts loading, because it&#8217;s not possible to do so yet.&#8221; That&#8217;s ludicrous.</p>
<p>LABjs is a self-admitted and proclaimed <strong>gap technology</strong>. It&#8217;s designed to meet an interim (and backwards-compatible) need &#8212; the need to drastically improve web performance optimization by parallel loading of scripts. And moreover, the need to normalize that behavior across ALL web browsers, not just the newest generation and ignore web performance for the older ones.</p>
<p>My hope always has been, and continues to be, that LABjs is someday made moot and unnecessary because all the browsers figure out a common way to handle things that serves all these use cases and needs in a performance-savvy way. And I spend countless hours and effort trying to advocate for such. It&#8217;s obviously frustrating when, either directly on purpose or just be accident, one browser vendor throws all that effort into jeopardy. That&#8217;s why I&#8217;m reacting with the candor that I am.</p>
<p>I continue to hope an amiable solution can be found. I hope that Mozilla is committed to the same. But chastising me on &#8220;right&#8221; and &#8220;wrong&#8221; like a little school boy and then offering no valid alternative is quite disingenuous.</p>
<blockquote><p>The plans have been <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#running-a-script" rel="nofollow">on display</a> in the cellar of the planning office for at least nine months.</p></blockquote>
<p>I&#8217;ve read this spec section many times. Just now reading it again, I found the one phrase which I&#8217;d missed in terms of interpretation on dozens of previous readings. &#8220;The element must be added to the set of scripts that will execute as soon as possible.&#8221;</p>
<p>I want you to notice something about that phrase. It&#8217;s a little bit ambiguous. At least from my perspective. It says that once a script loads, it should &#8220;execute as soon as possible&#8221;. But it doesn&#8217;t explicitly say that &#8220;as soon as possible&#8221; means to the exclusion of other previous dependencies.</p>
<p>If the interpretation of that phrase is that &#8220;as soon as possible&#8221; should be ignorant of things like previous dynamic scripts (insertion-order wise), then I submit to you that <strong>standard is wrong</strong>. It&#8217;s wrong because doing so completely ignores the use case of dynamically loading in parallel but preserving order &#8212; a use case that&#8217;s overwhelmingly self-evident for anyone who&#8217;s built web pages with more than one script file (like jquery and a single jquery plugin, for instance). We can have order preservation if the script tags appear in the HTML, but we can&#8217;t have order preservation if they are injected? That&#8217;s beyond silly.</p>
<p>I&#8217;m glad I now see exactly where this bad spec writing/interpretation is based off of. Prior to now, I&#8217;ve been unable to see anything in the spec that remotely resembles the spec indicating proper behavior between multiple dynamic scripts. But I strongly assert that the spec is wrong (or incomplete) in that respect. And implementing a part of the spec that has ambiguous interpretation at best and doing so in a way that completely ignores other important and valid use cases and needs is, in my opinion, somewhat irresponsible.</p>
<p>So I&#8217;d say this: you have the right (and responsibility) to implement spec. But what if spec is wrong? What if the spec fails to address the needs of the community? Should you still implement it and just look the other way? I say, no. I say there needs to be more community comment and involvement. I&#8217;m sorry I wasn&#8217;t around and part of the prior discussions when that phrase was added and agreed to, but nevertheless, the spec is going to cause some seriously negative waves for a lot of us if its implemented as currently interpreted and only that.</p>
<blockquote><p>
&#8230;..jQuery&#8230;.. </p>
<p>So I was doing what the standard says in order to fix site breakage. That&#8217;s about as righteous as browser engine changes can be.</p></blockquote>
<p>Agreed. I&#8217;m glad you implement spec. No one is criticizing that. But implementing things which have other major negative side effects, or even just things which are open to possible other interpretations or further discussion, without engaging the community you will directly affect, is not what I&#8217;d call wise and prudent behavior.</p>
<blockquote><p>As for not engaging you, there were three reasons for not engaging you: First, I was unaware of you. (The Web is pretty big!) Second, I was in a hurry. Third, the change I was making made Gecko behave like WebKit and IE (well, not exactly apparently for the non-script type thing), so it was relatively safe to assume that sites wouldn&#8217;t break since sites on the Web usually are already taking IE-compatibility and WebKit-compatibility into account. Of course, such reasoning only works for estimating the breakage risk for sites that run the same code path in all browsers. If you UA-sniff, your code may break, so please, please, don&#8217;t UA sniff.</p></blockquote>
<p>&#8220;Unaware&#8221;. Ok fair enough. LABjs isn&#8217;t as popular as jQuery, nor do I work for Mozilla like John Resig does. But LABjs is not an obscure unknown project either. It&#8217;s on the radar of some pretty big sites, and dozens of other big sites have expressed curiosity in experimenting with it. It&#8217;s on a bunch of blogs, it&#8217;s in a bunch of JavaScript conference talks I&#8217;ve given&#8230; blah blah blah. I don&#8217;t think it&#8217;s unreasonable to assume that LABjs has enough presence that due diligence in the area of script loading and order preservation should have surfaced it on the radar.</p>
<p>&#8220;In a hurry&#8221;. Well, we all make our mistakes, right? Everything about LABjs has been the opposite of being in a hurry. The topic in general is so ridiculously over complex due to all the quirks, it&#8217;s prudent to do anything but be in a hurry about it.</p>
<p>&#8220;Gecko like IE/Webkit&#8221;. What about Opera? Opera has operated like you (preserving script order) for as long as I&#8217;ve been paying attention. Did you think that maybe there was a reason why Opera did it that way too? Did you consider the effects of abandoning that behavior and leaving Opera as the only odd-one out would do to the script-loader part of the commmunity? You yourself admit that you took one area to adhere to IE/Webkit, but other adjacent things (however right or wrong) you didn&#8217;t adhere to. This is a common truth &#8212; doing part of the work can sometimes be worse than doing none of the work.</p>
<blockquote><p>New Twitter works fine in Minefield. Vimeo seems to work on Mac. (There are problems on 64-bit Linux, but I&#8217;m guessing those are related to out-of-process plug-ins.) Zappos isn&#8217;t obviously broken, but I didn&#8217;t try to order anything from there.</p>
<p>In fact, so far, there&#8217;s been no reports of actual site breakage arising from the Gecko script loader change that&#8217;d have reached me.</p></blockquote>
<p>Referencing surface testing of the sites I mentioned and seeing no observed site breakage, and asserting that as evidence is a pretty weak &#8220;inference&#8221; to whether or not the site is or will be affected by the change. Why? Because I know specifically in those 3 sites cases, they are not <strong>yet</strong> using the &#8220;preloading&#8221; (they have that feature flag turned off). But they are all intending to use it in the near future. Again, as I&#8217;ve asserted before, LABjs is only useful when considered as a performance script loader for dynamic parallel loading and ordered execution. </p>
<p>When you turn off &#8220;preloading&#8221;, LABjs becomes a pretty dumb and useless script (in fact, sometimes less performant than the manual &lt;script> tags alternative). The only reason any of those sites heard about or care about LABjs is for its potential performance accelerations. Just serial on-demand script loading is pretty trivial and been done much better by others long before I came around.</p>
<p>It&#8217;s quite valid and defensible why these major sites are rolling out their LABjs support and feature-usage little-by-little. There&#8217;s various reasons for Twitter and Vimeo doing things as they are now. But I know and regularly communicate with their developer teams, and I&#8217;m actively working on helping them get to the next (and more ideal) level.</p>
<p>I can tell you unequivocally that if any of those sites were to enable &#8220;preloading&#8221;, they would immediately break in Minefield. What this means, if we can&#8217;t figure out a resolution, is that those sites may never be able to turn on &#8220;preloading&#8221;, which means they&#8217;ll probably be well advised to just abandon LABjs going forward.</p>
<p>Moreover, if you want actual sites that use LABjs that break in Minefield, take this blog site and also <a href="http://flensed.com">flensed</a> as two examples. Notice that if you load either of them in Minefield, some things break, like the code that does the Twitter feeds, etc. There are lots of other sites using LABjs with &#8220;preloading&#8221;, and 100% of them will break in Minefield. So if real world examples are in need, I&#8217;ll be happy to point more to you besides the two just mentioned.</p>
<blockquote><p>Since reports of concrete site brokenness are absent, could it be that sites aren&#8217;t actually relying on the in-order property that LABjs tries to provide?</p>
<p>Do authors actually need to? In practice that is. Aren&#8217;t libraries that one might want to load already designed so that they don&#8217;t have loading-time inter-dependencies if you wait until all the libs have loaded before calling the APIs they provide?</p></blockquote>
<p>No, again, unequivocally the opposite is true of the real world. It&#8217;s very rare that you see (even production) sites that will bundle all of jQuery and all of jQuery-UI and all of the dozen associated plugins for each, all into one file. What usually happens is they load jQuery and jQuery-UI both separately from the Google CDN location, and then they load one or two local scripts from their server that have all the plugins and their own site logic contained. This is far and away the more common use case for the majority of the internet. Only the most high-end traffic sites self-host such resources and package them all into a single file.</p>
<p>And no, it&#8217;s not reasonable to assume that all the scripts which are out there that DO currently have load-order dependency must all simultaneously be re-written because of one change made by one browser vendor. We have to be pragmatic and continue to support the way the web currently (and has for a long time and will for a long time) works.</p>
<blockquote><p>Am I inferring correctly that you wouldn&#8217;t want script-inserted scripts to block parser-inserted scripts?</p>
<p>Do you <i>really</i> want script-inserted external scripts to block script-inserted inline scripts and parser-inserted scripts? Or do you just want script-inserted external scripts to maintain order among themselves?</p></blockquote>
<p>Here&#8217;s what I don&#8217;t want: I don&#8217;t want an inserted script node to have <strong>any</strong> dependencies on anything else in the document, <strong>except</strong> other inserted script nodes.</p>
<p>I understand that jQuery&#8217;s use case for &#8220;global Eval&#8221; uses inserted &#8220;inline&#8221; scripts and that the blocking of such logic is undesired. I think there should be some sort of flag settable on such scripts to inform the browser of the need for immediate execution.</p>
<p>But I have a completely different use case, one that is extremely common on the majority of the web. It is that people often times will have what I call &#8220;script tag soup&#8221;, which is that they will have several script tags (external src references) and then an inline script tag with some logic, and then possibly more external script tags and then more inline script tags, etc. They have these tags strewn all over the HTML source (for various reasons, including CMS&#8217;s, templating limitations, etc).</p>
<p>Steve Souders gave a term for the idea of replacing an inline script block with something that would execute in the proper order after a dynamic script was loaded&#8230; it&#8217;s called &#8220;coupling&#8221;. LABjs&#8217; entire stated goal is to replace &#8220;script tag soup&#8221; with dynamically loaded (and yes, if need be, properly &#8220;coupled&#8221;), script loading alternatives. For instance, this blog post I did late last year on <a href="http://blog.getify.com/2009/11/labjs-how-to-deal-with-inline-code/">using LABjs to deal with inline script blocks along side dynamically loaded external resources</a> shows such a common usage pattern.</p>
<pre class="code">
&lt;script src="framework.js">&lt;/script>
&lt;script src="myscript.js">&lt;/script>
&lt;script>
  myscript.init();
&lt;/script>
&lt;script src="anotherscript.js">&lt;/script>
&lt;script>
  another.init();
  framework.init();
  framework.doSomething();
&lt;/script>
</pre>
<p>To use LABjs to deal with that &#8220;script tag soup&#8221; (both the external dynamic loadings and the &#8220;coupled&#8221; inline scripts), you do this:</p>
<pre class="code">
&lt;script>
  $LAB
  .script("framework.js")
  .script("myscript.js")
  .wait(function(){
     myscript.init();
  })
  .script("anotherscript.js")
  .wait(function(){
     another.init();
     framework.init();
     framework.doSomething();
  });
&lt;/script>
</pre>
<p>So, I&#8217;d say, <strong>yes</strong>, &#8220;coupling&#8221; of inline scripts to execute in the proper order along with externally loaded scripts is very important.</p>
<p><strong>HOWEVER</strong>, this issue is quite confused, because LABjs does not actually use injected inline scripts to handle how this &#8220;coupling&#8221; works. Because a function is passed to the .wait() function, that function can simply be executed with no need for an inserted inline script node.</p>
<p><strong>ON THE OTHER HAND</strong>, LABjs does in fact do some &#8220;inline script insertions&#8221; for some browsers (not Mozilla). For <strong>local scripts</strong> that are preloaded in IE/Chrome/Safari using local XHR, those scripts are executed at the proper time in the chain by creating an inline script node and injecting the loaded source code of the script into the node using the .text property.</p>
<p><strong>So, for THAT use case</strong> for IE/Chrome/Safari, I absolutely do hope that there&#8217;s still some way to make sure the injected code can execute right away when asked to, but I <strong>do not need</strong> to be able to inject that script node ahead of time and have the dynamic external scripts pay attention to it as far as order. As I said above, having an &#8220;execute immediately&#8221; flag (or behavior, as it currently seems) similar to jQuery&#8217;s &#8220;global Eval&#8221; use case would be more than sufficient.</p>
<p>To answer your question directly, I only want dynamically inserted script nodes to respect insertion order among themselves &#8212; nothing more. For Mozilla, I only use dynamically inserted external scripts, so for you guys, I don&#8217;t need the behavior of also preserving order with &#8220;inserted inline scripts&#8221;. But I do need the &#8220;immediate&#8221; execution of inline scripts for the other browsers&#8217; &#8220;preloading&#8221; tricks (for local files only) to keep working.</p>
<blockquote><p>This is exactly what&#8217;s happening. (Well, except the standard says &#8220;If the user agent does not support the scripting language given by the script block&#8217;s type for this script element, then the user agent must abort these steps at this point.&#8221;, so your bogus type trick doesn&#8217;t work according to HTML5.)<br />
&#8230;<br />
I now see that you posted to the WHATWG&#8217;s &#8220;help&#8221; mailing list in March. The WHATWG was already publishing a spec that covered the area and you didn&#8217;t ask for any changes, and you didn&#8217;t follow up to Hixie&#8217;s follow-up question, so the thread went nowhere.</p>
<p>To engage with browser vendors on this topic, I encourage you to join the W3C HTML WG. (There&#8217;s a better chance of engaging Microsoft there than on any of the WHATWG lists.)
</p></blockquote>
<p>As I asserted earlier, I have been tirelessly, for over a year, exploring how I can best advocate for practical standards to be written <strong>and</strong> implemented which are informed and aware of the various performance use cases that are at play. The attempts on the WHATWG mailing list, I was shot down immediately. I did follow up with several of those people in direct one-on-one emails, and overwhelmingly the response seemed to be &#8220;we don&#8217;t need standards for this&#8221;. They made no reference to the standard that was already there, they said no standard was needed. Obviously we do need it, so I considered that to be a brick wall. I only went to the WHATWG in the first place because someone suggested that it&#8217;d be a better place to address this topic than the W3C.</p>
<p>When WHATWG failed to be receptive to my call for a discussion, I then pursued another avenue. I have had several email exchanges with Brendan Eich and various others he CC&#8217;d (including some people from Yahoo, I believe) to try and get the discussion rolling. While the group seemed to be receptive to the need for such discussions, the discussions themselves have yet to go anywhere productive. It wasn&#8217;t a brick wall like WHATWG, but it&#8217;s yet to produce any useful results.</p>
<p>I even tried (a month ago) to join the new W3C Web Performance WG, again hoping that they would be a good platform to start pushing this discussion. I&#8217;ve yet to hear back from them on my application to join.</p>
<p>So, in the mean time, I&#8217;ve been continuing to advocate (via Twitter, blog posts, and conference speakings) for more awareness and action on this issue. I&#8217;ve done everything I can to make LABjs and the need for performance script loading as wide-spread known as possible. Steve Souders has endorsed LABjs on several occasions, and I believe he also would agree there&#8217;s need to come up with a standard everyone can agree on, <strong>as long as that solution doesn&#8217;t ignore the needs of the web performance community</strong>.</p>
<p>I have no problem with trying to also join the W3C. But please don&#8217;t accuse me (wrongly) of inaccurate claims in my saying that I&#8217;ve been pushing for advocacy and awareness on this topic in a lot of different avenues for quite awhile. I don&#8217;t have a very well known or influential voice, but I&#8217;m every bit (or more) passionate as anyone else on having a productive discussion with all the players so that a good solution can be found.</p>
<blockquote><p>It seems you aren&#8217;t too happy now that such standardization and implementation is happening <img src='http://getiblog.2static.it/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' /> </p></blockquote>
<p>I&#8217;m only unhappy because the interpretation of spec as currently written seems to be ignorant of a very important and wide-spread use case, and because the process by which vendors like Mozilla are implementing that (in my opinion, ill-conceived) spec is not properly engaging the community (like myself) to make sure that important facts aren&#8217;t being bull-dozed over.</p>
<blockquote><p>Reverting the Gecko change and pushing for the old Gecko behavior to be standardized. This would re-introduce the problems the change was meant to solve, so I think this isn&#8217;t a real option, either. Furthermore, to get to interop via this path, IE and WebKit would have to change substantially.</p></blockquote>
<p>Because I have always believed that Firefox and Opera were <em>right</em> all along in this behavior, I&#8217;d be far more in support of reverting to the previous way and getting the other browsers to agree to follow suit. All the ugliest part of the hacks in LABjs (the &#8220;text/cache&#8221; junk) is all to deal with how to preload remotely when order isn&#8217;t already enforced. So in my opinion, the direction of Mozilla (and the spec) on this is opposite of the right direction. It may be harder to get the others to agree, but I think it&#8217;s more <em>right</em> than what is happening now.</p>
<blockquote><p>Making Gecko enforce insertion order execution of script-inserted external scripts that don&#8217;t have the async attribute among themselves and standardizing that. This solution looks attractive on surface, but this isn&#8217;t a good solution. A library like LABjs wouldn&#8217;t be able to capability sniff whether scripts will execute in insertion order (even if you tried to load some scripts and saw in-order execution, you couldn&#8217;t be sure it wasn&#8217;t by chance). A solution that relied of UA sniffing wouldn&#8217;t make JS libraries put future IE or WebKit on the new code path when IE or WebKit started enforcing insertion order execution.</p></blockquote>
<p>I agree this isn&#8217;t ideal or a long-term solution, but doing so for now (basically, going back to the way it was) might be a decent solution until we can all have time to figure out the better long term solution that suits everyone.</p>
<blockquote><p>Adding a DOM-only boolean property called &#8220;ordered&#8221; to script element nodes. This property would default to false. JS libraries could capability sniff for the presence of the DOM property to see if it is supported and set it to true to request script-inserted scripts that have the property set to true execute in insertion order among themselves (but not blocking other scripts). If we address your use case at all, this is the best solution I&#8217;ve come up with so far. Note that this would give IE and WebKit a capability-sniffing upgrade path to getting to the code path that doesn&#8217;t require bogus type preload.</p></blockquote>
<p>I recognize this as a possible (and perhaps valid and viable) solution. I think more needs to be discussed on it or other similar approaches. I have some concerns, but nothing that would probably be a deal-breaker on that path.</p>
<blockquote><p>(I realize that it looks offensive to say &#8220;If we address your use case at all&#8221;, but doubting the need to address a use case is a healthy standard operating procedure. After all, so far actual breakage of concrete existing sites hasn&#8217;t been shown.)</p></blockquote>
<p>It&#8217;s fine to doubt and to discuss. It&#8217;s not ok to doubt and <em>not</em> discuss, which is what it felt like was happening before and why I reacted so strongly. If Mozilla will commit to opening up a public forum discussion and helping to get all the other browsers involved in that discussion so we can all agree on something that works for everyone, <strong>that to me is the ideal long-term resolution</strong>.</p>
<p>In the short-term though, we need to figure out what&#8217;s going to happen with FF4 scheduled to release in just a few weeks as I understand it.</p>
<h3>Summary</h3>
<p>I appreciate the Mozilla developer(s) beginning to engage in this discussion. I hope the end result is that a productive dialog can be had with all of us on equal footing and all important use cases addressed. That&#8217;s the only thing I&#8217;m calling for right now. Well, that and &#8220;what do we do about the short-term FF4 change?&#8221; I have an enormous amount of respect for Mozilla, but I hope the same courtesy can be granted of others like me who aren&#8217;t so &#8220;in the loop&#8221; but have valid concerns nonetheless.</p>
<div><a class="addthis_button" href="//addthis.com/bookmark.php?v=250" addthis:url='http://blog.getify.com/mozilla-labjs-part-2/' addthis:title='Mozilla &amp; LABjs&#8230; part 2 '><img src="//cache.addthis.com/cachefly/static/btn/v2/lg-share-en.gif" width="125" height="16" alt="Bookmark and Share" style="border:0"/></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.getify.com/mozilla-labjs-part-2/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Mozilla &amp; LABjs: The story unfolds</title>
		<link>http://blog.getify.com/mozilla-labjs-the-story-unfolds/</link>
		<comments>http://blog.getify.com/mozilla-labjs-the-story-unfolds/#comments</comments>
		<pubDate>Thu, 07 Oct 2010 14:31:05 +0000</pubDate>
		<dc:creator>getify</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Performance Optimization]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[labjs]]></category>
		<category><![CDATA[loader]]></category>
		<category><![CDATA[mozilla]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[script loading]]></category>

		<guid isPermaLink="false">http://blog.getify.com/?p=577</guid>
		<description><![CDATA[If you&#8217;re not yet up to speed on the drama with the new FF4 nightly (aka &#8220;minefield&#8221;) and how it affects the performance functionality (&#8220;preloading&#8221;) of LABjs, I encourage you to read that previous post. Brief Summary LABjs has a performance oriented feature (pretty much the 98% reason why LABjs even exists) called &#8220;preloading&#8221; which [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re not yet up to speed on the <a href="http://blog.getify.com/2010/10/ff4-script-loaders-and-order-preservation/">drama with the new FF4 nightly</a> (aka &#8220;minefield&#8221;) and how it affects the performance functionality (&#8220;preloading&#8221;) of <a href="http://labjs.com">LABjs</a>, I encourage you to read that previous post.</p>
<h3>Brief Summary</h3>
<p>LABjs has a performance oriented feature (pretty much the 98% reason why LABjs even exists) called &#8220;preloading&#8221; which allows it to load all of a site&#8217;s scripts in parallel, but ensure their execution order (if needed/expressed) for dependency sake. Because the browsers all have different behavior on this topic, LABjs has a bunch of ugly gory stuff in its guts to smooth out the differences, using different tricks for different browsers. </p>
<p>The &#8220;trick&#8221; in question with the Mozilla line of browsers (FF, etc) is that &lt;script> tags inserted dynamically into the browser (always have up to this point) preserved insertion-order for execution. As a matter of fact, that behavior is the <strong>most desirable</strong> behavior with respect to script loaders being used for improving site performance. But Mozilla has now dropped that behavior, and left us nothing in its place, meaning that LABjs&#8217; performance functionality (again, the main and almost only feature) has been crippled for FF4 going forward.</p>
<h3>Mozilla&#8217;s response</h3>
<p>So, I wrote that post a couple of days ago to try and surface within the community the importance of this issue and try to get Mozilla involved in a discussion about how to resolve this difficult turn of events. The primary developer from Mozilla who is responsible for that change in behavior has now <a href="http://blog.getify.com/2010/10/ff4-script-loaders-and-order-preservation/comment-page-1/#comment-748">responded with a pretty lengthy explanation/admonition</a>. I encourage you to go read that comment in full (almost as long as my original blog post). But I&#8217;m writing this post here to respond to the things said there. It&#8217;s long and involved and so needs its own post to do it justice.</p>
<p>Before I go into specific detail to address the points raised in that comment, I want to just give a general response as a summary to my feelings on what was said.</p>
<p>The comment goes into exquisite detail to chastise me for improper behavior regarding &#8220;UA sniffing&#8221; (and similar approaches), basically suggesting that the turn of events that have left LABjs in turmoil are basically expected and warranted given the approach that I took with how LABjs does its magic. The comment does have <em>some</em> cordial language to suggest that Mozilla is willing to further discuss possible ways forward, but the clear overall tone is that LABjs should never have done things the way it did, and that the primary use case that LABjs was designed to serve is dubious/questionable at best.</p>
<h3>Salvo</h3>
<p>So let me just respond to that as a general tone of the comment.</p>
<p>LABjs has been around for about 15 months now. It&#8217;s been written up numerous times in Ajaxian.com, featured on many different blog posts (my own and several others), mentioned in a couple of different books, talked about relentlessly by me at JavaScript conferences around the world and through Twitter, endorsed by leading performance-optimization voices like Steve Souders, and now even powering JavaScript loading on some of the web&#8217;s biggest sites, like <a href="http://twitter.com">(new) Twitter</a>, <a href="http://vimeo.com">Vimeo</a>, and <a href="http://zappos.com">Zappos</a>. In addition to those big sites, I&#8217;m personally aware of <em>hundreds</em> of other sites of varying size/reach that are also using LABjs to load their scripts. I of course have LABjs running on a dozen or so of my own sites, including this blog.</p>
<p>In nearly 100% of the cases, including comments even in LABjs&#8217; own source code and documentation on the site, I&#8217;ve proclaimed and admitted that the biggest &#8220;problem&#8221; that the web community has in terms of performance-oriented script loading is the browser fragmentation on how dynamic, parallel-loading of resources works. Script loading is not why LABjs exists. <strong>Script loading in a performance-savvy way is why LABjs exists.</strong> It&#8217;s an <strong>exceedingly</strong> complex task to try and load multiple scripts (of any sort and location, not just those specially prepared) in parallel, and ensure execution order, and do so with both local and remote scripts, and do so on-demand (that is, either during page load or later), <em>and</em> normalize that behavior across all browsers. To my knowledge, no other script loader has ever achieved such a wide-spread task as that.</p>
<p>I don&#8217;t own the credit for recognizing this problem existed. That belongs much more to <a href="http://stevesouders.com">Steve Souders</a>. Steve is recognized as probably the most well-known and influential advocate for web performance that the web has today (and may ever have). In both of his books, &#8220;High Performance Web Sites&#8221; (HPWS) and &#8220;Even Faster Web Sites&#8221; (EFWS), he identified dynamic, parallel script loading as a very important use case that was not being well served on the majority of the web sites out there (both big and small). </p>
<p>I read both of those books diligently (and many times), and concluded that a generalized solution to performance script loading <em>must</em> be developed. In many ways, Steve is why LABjs was born. In fact, it was Steve who documented all the different fragmented behavior between browsers, and explored the various tools and tricks we had available to us to solve them. Unfortunately, he, like I, readily recognized that no such trick worked in all browsers. He presented code in EFWS (chapter 4 and 5) for how to begin addressing dynamic script loading, but admitted that the code was not general purpose enough for the masses and that more needed to be done.</p>
<p>Steve is the one who deserves credit for raising the awareness on the issues of dynamic parallel script loading, and for codifying the specific general use case that LABjs was designed to solve. In fact, he was instrumental in helping LABjs come to be, through several lengthy email threads, phone calls, in-person collaborations and brain-storming, etc.</p>
<p>You see, I didn&#8217;t develop LABjs in isolation in my basement. I went to one of the foremost authorities on these issues, and I studied what he had to say, and I worked countless hours to try and find a way to bring all the pieces together. In that process (over 5 months of development), I found a very delicate balancing act of tricks that solved the use case. Steve and I explored several possible alternatives, but eventually I decided that the way LABjs does things is the only currently workable solution that meets the goals of the project.</p>
<h3>Fork you</h3>
<p>And yes, this <strong>does</strong> require forking behavior between different browser families. But I&#8217;ve been a huge <strong>opponent</strong> of &#8220;UA sniffing&#8221; for years, including a <a href="http://www.nczonline.net/blog/2009/12/29/feature-detection-is-not-browser-detection/">rather lengthy disagreement comment-thread with Nicholas Zakas</a> on the topic, as well as many others. So, I am fundamentally opposed to UA sniffing, and I absolutely detest anything that even smells like it. Of course I agree that feature-testing is the right way to go.</p>
<p>But there is no feature-test for the quirky behavior of different browsers with respect to how they load external resources dynamically, cache them, fire load events, etc. It&#8217;s one of those rare niche cases where feature-testing does not fit the bill. So the next best thing, in my opinion, is to use <strong>browser inference</strong> to fork the behavior between browsers. Essentially, this involves an indirect feature-test, by feature-testing for something known to belong only to one (or one set of) browser family(ies), and then based on that inference, relying on the previously observed behavior.</p>
<p>Is this foolproof? Hardly. It is a good idea? No, it&#8217;s a terrible idea. But in this case, no other even remotely acceptable alternative exists. It&#8217;s not an option, in my opinion, to simply <em>not solve this use case</em> now, as the other comment suggests. It&#8217;s not practical to have entirely different loaders for each browser, and force the web site to some how figure out (through server-side UA sniffing no doubt) which loader to use. <strong>UA sniffing AND browser-inference suck, but for LABjs, inference was the only option.</strong></p>
<p>So, all this is to say, I understand the admonitions of the other comment against UA sniffing and related ilk. I don&#8217;t like them either. But I&#8217;m not some inexperienced script kiddie that has no clue. I&#8217;ve spent over a year trying to specialize in this area, and this is the best that I (and other far greater minds than me) could come up with. So while I appreciate the wisdom of avoiding such techniques when possible, I&#8217;d submit to you that it&#8217;s rather condescending to suggest that I simply was foolhardy and ignorant and that LABjs was destined for such failure as a result of my ill-advised approach. For the last 15 months, LABjs has been radically improving the web performance of hundreds or thousands of sites, and doing so carefully balanced on the tenuous tight rope of distinct browser quirks.</p>
<h3>Call it what it is</h3>
<p>The problem is not that LABjs relies on less-than-ideal practices to exploit quirks in various browsers. The problem is that the various browsers have persistently, for years, failed to find an agreement on how such resources can be loaded with performance optimization and flexibility as the primary concern. Even now, in that comment, the admission is clear: we can&#8217;t solve this use case with the current state of standards nor with the current state of web browser technology.</p>
<p><strong>LABjs is a <em>gap technology</em> designed to fill the holes that browsers have carelessly left open.</strong> LABjs is designed to bring web performance optimization to web sites and scripts of all kinds <strong>right now</strong>, while we wait for browsers to catch up to that trend. The key assumption is of course that browsers will take note of that trend, and of the validity of the need, and will participate in the process. And I&#8217;ve done everything I can humanly do to advocate for that, in the shadows of greats like Steve Souders.</p>
<h4>[deep breath]</h4>
<p>OK, now that that&#8217;s off my chest, I need to address many other specific points in the Mozilla developer&#8217;s comment. But this post is already too long. So, I&#8217;m going to cut it here, and follow up with a second post (&#8220;part 2&#8243;), right away. So stay tuned.</p>
<p><strong>[UPDATE] Please continue down the rabbit hole with <a href="http://blog.getify.com/2010/10/mozilla-labjs-part-2/">Part 2 of Mozilla &#038; LABjs</a>.</strong></p>
<div><a class="addthis_button" href="//addthis.com/bookmark.php?v=250" addthis:url='http://blog.getify.com/mozilla-labjs-the-story-unfolds/' addthis:title='Mozilla &amp; LABjs: The story unfolds '><img src="//cache.addthis.com/cachefly/static/btn/v2/lg-share-en.gif" width="125" height="16" alt="Bookmark and Share" style="border:0"/></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.getify.com/mozilla-labjs-the-story-unfolds/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Simulated Chaining in JavaScript</title>
		<link>http://blog.getify.com/simulated-chaining-in-javascript/</link>
		<comments>http://blog.getify.com/simulated-chaining-in-javascript/#comments</comments>
		<pubDate>Wed, 10 Feb 2010 16:18:04 +0000</pubDate>
		<dc:creator>getify</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[chaining]]></category>
		<category><![CDATA[functions]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[labjs]]></category>

		<guid isPermaLink="false">http://blog.getify.com/?p=213</guid>
		<description><![CDATA[What I have to talk about here is not going to be earth shattering, but it is a technique that has proved useful in a few different sites and scenarios for me. In fact, I regularly get questions regarding advanced use cases for LABjs (a parallel JavaScript loader), and invariably it comes back to something [...]]]></description>
			<content:encoded><![CDATA[<p>What I have to talk about here is not going to be earth shattering, but it is a technique that has proved useful in a few different sites and scenarios for me. In fact, I regularly get questions regarding advanced use cases for <a href="http://labjs.com">LABjs</a> (a parallel JavaScript loader), and invariably it comes back to something along these lines.</p>
<p>If you already understand object/function call chaining, just <a href="#goodstuff">skip down to the good stuff</a>.</p>
<h2>The chains that bind you</h2>
<p>Just so we&#8217;re all on the same page, &#8220;chaining&#8221; is this wonderful functional property of languages like JavaScript (which treat a function as a first-class citizen). It essentially amounts to making a function call, and the return value from the function is itself either another callable function, or more often, an object that has functions which are directly callable.</p>
<p><a href="http://jquery.com">jQuery</a> is probably the most prevalent use of this concept. Some example jQuery code:</p>
<pre class="code">
$("p.neat").<strong>addClass</strong>("ohmy").<strong>show</strong>("slow");
</pre>
<p>In this snippet, <code>$(...)</code> is actually a function call, just like <code>foo(...)</code> or <code>doSomethingReallyEvilButDontTellAnyone(...)</code> (just kidding; only Google would name a function something crazy like that).</p>
<p>The return value from the <code>$(...)</code> call is an object, that has a bunch of properties on it, many of whom are functions. Consider that conceptually an object is returned like this (not actual code):</p>
<pre class="code">
function $(...) {
   // do something cool
   return {
      addClass:function(...){...},
      show:function(...){...},
      ...
   };
}
</pre>
<p>So, what happens is that when that object is returned from the function, JavaScript will allow you to immediately <em>de-reference</em> the return value (the object), and using &#8220;.&#8221; (dot notation), access its properties. So <code>$(...).<strong>addClass(...)</strong></code> makes the first chained call (&#8220;addClass&#8221;) off the return value from <code>$(...)</code>. Then, <code>addClass(...)</code> also returns the same (same kind, not identical) object, and so this second return value can identically be de-referenced and a chained function be called. I like to refer to each chained function call as a &#8220;chain link&#8221;.</p>
<p>This chaining can theoretically go on forever (although for code readability it can be argued that 3 or 4 chain links is probably the most you want to practically do in production code, exceptions aside).</p>
<h2>Why chains?</h2>
<p>Probably the single biggest argument for developing code API&#8217;s that are of this chaining style is to pass context along from one function call to another in an automatic and graceful feeling way. For instance, in jQuery&#8217;s case, the reason for chaining is that internally, there&#8217;s a collection (a fancy array) of objects, and as each chained function is called, internally it loops over the collection of objects and performs tasks (such as expanding/contracting the collection, modifying objects in the collection, etc).</p>
<p>jQuery could work functionally this way and achieve the same effect:</p>
<pre class="code">
var collection = $("p.neat");
$.addClass(collection,"ohmy");
$.show(collection,"slow");
</pre>
<p>See how we had to pass in the &#8220;collection&#8221; object/array for every function call? It works, but that code is arguably a little less graceful. And certainly it&#8217;s a little more repetitive.</p>
<p>So, chaining was a way to accomplish the same task (context passing across function calls) but in a prettier, more graceful fashion. Generally, the idea of adjusting the way a set of code works to make it more expressive or pleasant is called adding &#8220;syntactic sugar&#8221;.</p>
<p>To be fair, syntactic sugar is not the only reason why chaining in functional languages is useful. In fact, with LABjs, which also has a similar type of chaining API (although internally operates quite differently from jQuery), the reasons were only partially &#8220;sugar&#8221;; chaining in LABjs&#8217; case actually provides an effective solution to guard against certain types of race conditions. </p>
<p>Because of how JavaScript (single-threaded) works, a chain of function calls is more or less guaranteed to complete fully before any other code comes in and interrupts to execute. This is also <em>probably</em> true of a series of distinct function calls in a single code block, but even more definitely so for a chain of function calls or (as we&#8217;ll see in a moment), a loop of function calls.</p>
<h2>So why not a chain?</h2>
<p>Since chains are powerful and also tend to lead to more expressive code (unless abused) and also generally <em>less code</em>, you may wonder, why wouldn&#8217;t we always use chains for everything?</p>
<p>The obvious: some function calls are, by their nature, independent and thus do not need to (or should not!) share a context. Also, under certain circumstances, chaining can be less efficient internally, depending on how the context is stored/shared/used.</p>
<p>Let&#8217;s face it: if you really want to write your entire &#8220;program&#8221; on one line with a bunch of obscure/abusive syntactical tricks, just go write some Perl. I kid, I kid.</p>
<p>But beyond those things, one fundamental fact of chaining is that it&#8217;s not &#8220;dynamic&#8221;. Basically, what I mean by this is that you pretty much hard-code at the time of code writing (aka, &#8220;build time&#8221;) how a chain is constructed. You can&#8217;t decide at run time based on environmental conditions that some parts of the chain are conditionally not executed (like by wrapping them in an if-statement, etc). </p>
<p>The ability to do that kind of run-time logic is restricted syntactically to individual statements/function calls, so a chain will be considered an atomic single indivisible unit for those purposes. You could conditionally decide whether to run one of several different chains depending on conditions, but each chain to be chosen would be pre-defined and for the most part immutable.</p>
<p>So, the truth is, chaining provides a syntactically prettier (more expressive) code approach, but it limits us a little bit in terms of coding flexibility.</p>
<h2>I need more concrete</h2>
<p>To illustrate, let&#8217;s revisit jQuery&#8217;s example code from above. Let&#8217;s say instead that what you really want to do is only run the <code>addClass(...)</code> call if some condition is true (like for instance, the user has a valid login session, or whatever). So, you want to basically do conceptually something like this:</p>
<pre class="code">
$("p.neat")
<strong>if (userLoggedIn()) {</strong>  .addClass("ohmy")  <strong>}</strong>  // invalid syntax; will not work!
.show("slow");
</pre>
<p>As I mentioned, you could just have two different chains, one with <code>addClass(...)</code> in the chain, one without it, and choose which chain to execute with your if-statement. This leads to more and repetitive code; a bad thing. DRY (don&#8217;t repeat yourself).</p>
<p>And to be honest, you could also model this in a pure jQuery way (only in the chain using various filters), a variety of different ways. For instance, something like this (while ugly) might work:</p>
<pre class="code">
$("p.neat")
.filter(function(){
   return isLoggedIn();
})
.addClass("ohmy")
.end() // ends the most recent filtering operation
.show("slow");
</pre>
<p>What I did here was use <code>filter(...)</code> to basically conditionally empty out the internal collection if not logged in (by returning false for all iterations), meaning the <code>addClass(...)</code> call is essentially ignored, and then revert back to my original collection with a <code>.end()</code> call before lastly calling <code>.show(...)</code>.</p>
<p>Let me be clear: while you <em>can</em> do it this way, this is by far not the most efficient or code-friendly way to do so. This would be an example of an anti-pattern, where you are abusing jQuery&#8217;s syntax to solve a problem in a way that it should not be solved. It goes contrary to the spirit of jQuery (&#8220;write less, do more&#8221;).</p>
<h2>Other examples?</h2>
<p>Conditional inclusion of &#8220;chain links&#8221; is only one scenario where traditional chaining is kind of limiting. What if you want to be able to piece together different parts of a chain from various different snippets of code across mutliple functions? This may sound strange, but with complex Web 2.0 web applications, this kind of thing is not uncommon. And it flys in the face of the simple syntactic sugar that chaining is supposed to give us.</p>
<p>Nor are these problems limited to jQuery. With LABjs for instance, a chain might look like this:</p>
<pre class="code">
$LAB
.script("framework.js")
.script("loggedin.js")
.wait(function(){
  // do something
});
</pre>
<p>Notice there I may want to <em>only</em> load &#8220;loggedin.js&#8221; if the user is, in fact, logged in. Same syntactic problem as above. But LABjs has no conditional &#8220;filters&#8221; that can modify the chain&#8217;s context, so we have less options (which in this case is a good thing!)</p>
<p>Or, what if I have a CMS system (like WordPress for instance) that, across various functions, files, templates, etc, needs to load up a variety of different files, all based on various different environmental conditions and which templates are active, etc. Could I do individual $LAB chain calls in each location? Yes. But then I lose the ability to sequence the loads (ensure execution order). Also, it&#8217;s less memory efficient to do 8 different chains with 1 script in each, as opposed to one chain with 8 scripts in it.</p>
<p>Or, what if I want to use LABjs in a larger solution for <a href="http://happyworm.com/blog/2010/01/28/a-simple-and-robust-cdn-failover-for-jquery-14-in-one-line/">creating robust fallback for resource loading from CDN locations</a>? I need to conditionally decide during loading/run-time if I need to add more scripts to the &#8220;queue&#8221; because one load failed. Not possible with traditional chaining.<br />
<a name="goodstuff"></a></p>
<h2>Unravel the ball of yarn</h2>
<p>All this leads up to say that chaining is great and expressive and powerful, but it&#8217;s not complete for all our needs. So, we need to get a little more creative in those cases. And this technique is what I&#8217;m going to call &#8220;Simulated Chaining&#8221;.</p>
<p>Recall that at the top of this post, we talked about how chaining works because the <em><strong>return value</strong></em> from a function is either a function itself (and thus can be called directly), or it can be an object that can be de-refenenced and has properties which are functions to be executed.</p>
<p>So, our solution lies in that sentence (emphasis added). The <em><strong>return value</strong></em> from a function can either be used immediately, or it can be stored and used later. This isn&#8217;t anything new; if you&#8217;ve ever called any function in any language, you know it can return a value that you can store in a variable. What might have escaped you until now is that this return value that you store can be a contextually sensitive object that would otherwise have been used immediately in a chaining situation. And the cool part is it can be used later (like the next loop iteration) to pick up where the chain left off.</p>
<p>So, instead of pre-defining a chain in our code/build-time, we can instead programatically (at run-time) build up a &#8220;list&#8221; (an array/queue for instance) of functions to be called, and then &#8220;simulate&#8221; a chain by looping through the list, calling each function, and storing the return value for use in the next iteration.</p>
<p>For instance, the LABjs script code above can be done like this instead:</p>
<pre class="code">
var queue = []; // empty array for now
...
queue[queue.length] = "framework.js";
...
if (isLoggedIn()) { queue[queue.length] = "loggedin.js";
...
var $L = $LAB;
for (var i=0, len=queue.length; i&lt;len; i++) {
   $L = $L.script(queue[i]);
}
$L.wait(function(){
   // do something
});
</pre>
<p>I <em>simulated</em> a chain of function calls with an iterative for-loop. (NOTE: this is conceptually very similar to how you might take what would otherwise be a recursive set of function calls and turn it into a non-recrusive, iterative loop instead, like for performance reasons). The key is: store the return value from a function call, and then use that stored value as the object that makes the next call. Plain and simple. And now more powerful as you can build up your chains at run-time in as complex a way as is necessary.</p>
<p>Theoretically, a very similar approach could be taken for the jQuery examples above. However, I&#8217;ll leave that as an exercise for the reader.</p>
<p>Let&#8217;s look at one last slightly more advanced example of how to use simulated chaining with LABjs (which is nearly identical to how I do it on several of my sites):</p>
<pre class="code">
var queue = [];
...
if (conditionOne()) {
   queue.push("framework.js",false); // false will create an empty .wait()
}
...
if (conditionTwo()) {
   queue.push("plugin1.js","plugin2.js",function(){
      // initialize plugins
   });
}
...
queue.push("mypage.js");
...
var $L = $LAB;
for (var i=0, len=queue.length; i&lt;len; i++) {
   if (typeof queue[i] === "function") $L = $L.wait(queue[i]);
   else if (queue[i] === false) $L = $L.wait();
   else $L = $L.script(queue[i]);
}
</pre>
<p>I specify a queue array that can have one of three types of entries: a [string] is interpreted as a script to load, a [false] is interpreted as an empty .wait() call, and a [function] is passed to a .wait(&#8230;) call. I can use any manner of complex logic to build up the queue, and then in one for-loop at the bottom of the page, simulate the chain by looping over the queue.</p>
<p>Hopefully this helps clear up some of the mysticism that is chaining and give you some other ways to approach the challenging use cases you may face in your code. Go forth and chain (or loop)!</p>
<div><a class="addthis_button" href="//addthis.com/bookmark.php?v=250" addthis:url='http://blog.getify.com/simulated-chaining-in-javascript/' addthis:title='Simulated Chaining in JavaScript '><img src="//cache.addthis.com/cachefly/static/btn/v2/lg-share-en.gif" width="125" height="16" alt="Bookmark and Share" style="border:0"/></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.getify.com/simulated-chaining-in-javascript/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Content Delivery Network via getiblog.2static.it

Served from: blog.getify.com @ 2012-05-18 09:43:46 -->
