<?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; optimization</title>
	<atom:link href="http://blog.getify.com/tag/optimization/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>&#8220;(pre)Maturely Optimize&#8230;&#8221; revisited</title>
		<link>http://blog.getify.com/pre-maturely-optimize-revisited/</link>
		<comments>http://blog.getify.com/pre-maturely-optimize-revisited/#comments</comments>
		<pubDate>Thu, 17 Feb 2011 06:40:05 +0000</pubDate>
		<dc:creator>getify</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Performance Optimization]]></category>
		<category><![CDATA[benchmarking]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[profiling]]></category>
		<category><![CDATA[script junkie]]></category>

		<guid isPermaLink="false">http://blog.getify.com/?p=761</guid>
		<description><![CDATA[I wrote an article for Script Junkie (Microsoft) awhile back, and it was just published this week: (pre)Maturely Optimize Your JavaScript. In it, I make several against-the-grain assertions, which not surprisingly have ruffled quite a few feathers. To start out with, I&#8217;m attacking head-on the prevailing &#8220;fear&#8221; around doing anything in your code that even [...]]]></description>
			<content:encoded><![CDATA[<p>I wrote an article for <a href="http://scriptjunkie.com">Script Junkie</a> (Microsoft) awhile back, and it was just published this week: <a href="http://msdn.microsoft.com/en-us/scriptjunkie/gg622887.aspx">(pre)Maturely Optimize Your JavaScript</a>. In it, I make several against-the-grain assertions, which not surprisingly have ruffled quite a few feathers.</p>
<p>To start out with, I&#8217;m attacking head-on the prevailing &#8220;fear&#8221; around doing anything in your code that even remotely <em>looks</em> like optimization, because the magical &#8220;Premature Optimization is the root of all evil&#8221; fairy will come and slap you silly. I argue that in fact &#8220;<strong><em>Immature</em></strong> Optimization is the root of all evil&#8221;, and what we should as devs be most concerned about is learning how to optimize <strong><em>maturely</em></strong>. Mature optimization requires engineer-like thinking, critical reasoning skills, pragmatic wisdom, and above all, the sense of how to properly achieve balance.</p>
<p>Contrary to some of the negative outcry from a few vocal members of the community, I do not think I&#8217;m advocating for anything that would rightly be considered &#8220;premature&#8221;. Some people say that any optimization is &#8220;premature&#8221; if you haven&#8217;t first seen that code fail under load in real conditions. To me, this is like learning to drive by driving first, having accidents, and correcting your driving as you go along.</p>
<p>That doesn&#8217;t mean data and benchmarking is not important &#8211;of course it is.</p>
<h3>Maturity</h3>
<p>But it <em>equally</em> means that the mature and right thing to do is to <em>ALSO</em> be aware of common pitfalls before you hit them, and strive to write code that avoids those bad patterns. Many developers shy away from such approaches because they (I believe wrongly) assume that all &#8220;code optimization&#8221; leads to uglier or harder to maintain code. While this may sometimes be true, to an extent, it&#8217;s not a hard objective fact, and there&#8217;s lots of optimizations that can become <em>default</em> in your coding style that do not significantly detract from the style of your code.</p>
<p>In fact, I believe the 7 comparison snippets (before and after) that I show in the article illustrate that, with a few very minor changes, changes which do not cause the code to become completely unmaintainable, you can improve the performance of your code, sometimes by just a tiny amount, or sometimes by a huge amount.</p>
<p><strong>In NO case would I advocate <em><u>significantly</u></em> uglier or harder to maintain code for only a 3-10% increase in speed, in code that is not very critical.</strong> But a balanced, performance-savvy perspective on every line of code you write will tend to help you avoid the pitfalls, and let you focus your valuable energies on much more important tasks.</p>
<p>Also, notice: I am <strong>not</strong> focusing on esoteric and minute micro-performance details (as some do, and many assumed I was). I made no mention of things like <code>array.push()</code> vs. <code>array[array.length]</code>, or <code>str += "..."</code> vs. <code>str = arr.join()</code>, or <code>++i</code> vs. <code>i++</code>, or <code>for (i=0; i &lt; arr.length; i++) {...}</code> vs. <code>for (i=0, len=arr.length; i&lt;len; i++) {...}</code>, etc etc etc.</p>
<p>The optimizations I focused on were more broad pattern and algorithmic in nature, rather than comparing native operators and functions to each other &#8212; a fruitless task these days, with the browser speed wars still raging strong.</p>
<h3>Profiling, &#8220;profiling&#8221;</h3>
<p>If you already have existing code that&#8217;s a potential candidate for some optimization TLC, as Paul Irish pointed out to me, the prudent thing to do is of course to employ a script profiler. There are several tools that can profile run-time JavaScript performance &#8212; for instance, IE9&#8242;s Developer Tools includes a built-in profiler. Just yesterday, I used it to help my co-workers track down a critical performance bug in one of our client projects.</p>
<p>I wish I had mentioned the process of profiling specifically in the Script Junkie article. It wasn&#8217;t really the point of the article &#8212; the point was, once you&#8217;ve identified a block of code to attack, here&#8217;s some easy ways to do it &#8212; but it would have been helpful to talk about briefly. Paul was right to point out that omission.</p>
<p>On the other hand, the other implied goal of my article was to say that sometimes, our own brains and critical thinking skills can be effective at &#8220;profiling&#8221; the code we&#8217;re writing, as we write it. I regularly find myself halfway through an implementation, and I realize that something I&#8217;ve done is likely to lead to some performance hit later. I find that it&#8217;s usually not too difficult to adjust my approach right as I&#8217;m coding.</p>
<p><strong>How do I so easily recognize a performance anti-pattern as I&#8217;m writing it?</strong> I understand and code with a performance-savvy mentality as my default. I also have plenty of previous experience to inform avoiding repeating mistakes. And most of all, I subscribe to the belief that I should always be trying to learn from others who are knowledgeable and passionate about performance, to gain from their experience and wisdom as well.</p>
<p>This is the same mentality I&#8217;m advocating for other developers to adopt. I call <em>that</em> &#8220;Mature Optimization&#8221;.</p>
<h3>Refactoring</h3>
<p>I&#8217;ve made the claim a number of times, and I stand by it: <strong>The TCO (Total Cost of Ownership) for non-performant code is higher than for performant code.</strong> In other words, pay a little bit now, by way of taking the effort to write performant code (where practical), the first time, or pay more later, if/when you have to refactor that code to address performance concerns.</p>
<p>First of all, in the corporate world (of which i&#8217;ve held many such jobs), you often don&#8217;t ever get the second chance to come back and fix that poorly written code that you have to just throw together to get it out on deadline. We tell ourselves we&#8217;ll always come back and fix the code later, but in reality, we often never get to. And if we <em>do</em> get to come back to it, it&#8217;s usually under extreme pressure because something fell apart in production under real load, and now your boss is pissed at you.</p>
<p><strong>Not only does performance refactoring cost, in general, &#8220;double&#8221; the time in coding (coding it once, then coding it again), but it also costs a lot more time when unfortunate but often inevitable regressions are introduced and must also be corrected.</strong> Performance &#8220;refactoring&#8221; is more risky.</p>
<p>And why do I make that assertion?</p>
<p>Because unit-testing is <em>not</em> the de facto standard in the corporate world like it should be. In fact, of the dozen or so jobs I&#8217;ve held in the corporate web-application industry in my career, maybe 1 or 2 of them actually took unit-tests seriously. Most of the time, full integration tests (and not even comprehensive) were the best tests we could ever get our boss to approve us time to write.</p>
<p>I know we&#8217;d all like to sit on happy island where unit-testing (or TDD) is a reality and we all have 100% test coverage. But it isn&#8217;t that way in the real world, by and large.</p>
<p><strong>When you don&#8217;t have proper unit-tests, performance &#8220;refactoring&#8221; is very risky.</strong> The conditions under which you are forced to do it conspire against you, and you&#8217;re just bound to mess something up, usually in a subtle way you don&#8217;t realize just then.</p>
<p>And, btw, <em>even if</em> you had a full regression test-suite that ran, and immediately notified you that your &#8220;refactor&#8221; just broke something, you still have to spend more time (often costly time) tracking down the cause of that regression, and the regression <em>that fix</em> causes, and so on&#8230; down the rabbit hole we go. </p>
<p>It&#8217;s crazy to think that internally refactoring a function&#8217;s implementation details would cause other side effects, right? Sure, because in the corporate world, we get plenty of time to write 100% high quality code with no shortcuts or assumptions. We never stoop to using a quick global variable instead of figuring out the proper closure-scoping approach, when our boss is breathing heavy down our neck. Our code is always perfectly self-contained and well-patterned, right? </p>
<p>Except, no it isn&#8217;t, because that&#8217;s why we have this performance bug cropping up in the first place &#8212; because we had to cut corners to get code out the door.</p>
<h3>Benchmarks</h3>
<p>Some vocal critics have accused my code snippets in my article as being &#8220;premature optimization&#8221; because the improvements I suggest are &#8220;micro&#8221; or won&#8217;t have any noticeable impact on performance. I disagree with that assertion. And I created some <a href="http://jsperf.com">jsPerf.com</a> tests to illustrate.</p>
<p>The first versions of my test were a little rough and ill-formed, and Rick Waldron pointed out those flaws. I believe I&#8217;ve adjusted these tests to more accurately depict the point that each snippet comparison in the article was trying to make.</p>
<p><strong>NOTE:</strong> these tests are not going to look like your typical tests where you are comparing two native operators or something low-level like that. In several cases, the algorithms between each test case are intentionally quite different. It <em>should</em> be obvious that one will run much quicker than the other, because it&#8217;s doing a lot less (or a lot different) kind of task. The whole basis for these examples in the article is to show how a common, natural code pattern that&#8217;s perfectly semantic and self-descriptive or &#8220;object-oriented&#8221; or whatever, can suffer from (sometimes subtle) performance degradation. And <em>sometimes</em>, an effective way to improve performance is to think about a slightly different pattern or algorithmic approach. I&#8217;m trying to help you &#8220;see the forest above the trees&#8221;.</p>
<ol>
<li><a href="http://jsperf.com/scriptjunkie-premature-1/3">test case: function call, inner loop</a></li>
<li><a href="http://jsperf.com/scriptjunkie-premature-2">test case: bulk operations or iterators</a></li>
<li><a href="http://jsperf.com/scriptjunkie-premature-3">test-case: $(this) or collection-faking</a></li>
<li><a href="http://jsperf.com/scriptjunkie-premature-4">test-case: scope lookup, cached or not</a></li>
<li><a href="http://jsperf.com/scriptjunkie-premature-5">test-case: prototype chain lookup, cached or not</a></li>
<li><a href="http://jsperf.com/scriptjunkie-premature-6">test-case: nested property lookup, cached or not</a></li>
<li><a href="http://jsperf.com/scriptjunkie-premature-7">test-case: dom append or dom-fragment append</a></li>
</ol>
<p>Each of those tests has a table below it for the captured/averaged <a href="http://browserscope.org">Browserscope</a> test-run results, per browser. For instance, consider the test results (so far) for the first test-case (&#8220;function call, inner loop&#8221;):</p>
<p><img src="http://getiblog.2static.it/wp-content/uploads/2011/02/test1-results.png" alt="" title="test1-results" width="600" height="101" class="aligncenter size-full wp-image-762" /></p>
<p>Consider the Chrome 9 results: 14,101 operations/sec vs. 15,607 operations/sec. That&#8217;s a difference of 1,506 operations/sec, which is 10.7% faster. What did I do between those two tests? I simply inlined the <code>isOdd()</code> implementation into the loop, instead of as a function call. Is 10.7% life shattering or huge? No, probably not. But it&#8217;s an example of a very common coding pattern which <em>is</em> slower. With slightly more thought, in the case where it was possible/appropriate to do so, we can speed things up by 10.7% and not cost much by way of development time, nor is the code appreciably harder to maintain.</p>
<p>And, if you find that you are writing code that is a little uglier, or maybe is a little less self-explanatory, and you&#8217;re worried that this code may cause you (or some other dev) a maintenance problem later, there&#8217;s a sure-fire easy solution: <strong>WRITE A FRIGGIN&#8217; COMMENT TO EXPLAIN WHY THE CODE NEEDS TO BE THAT WAY.</strong></p>
<p>In fact, let me just say this: if you follow my advice and code with performance patterns in mind from the start, and you find yourself writing a piece of code that is just horribly uglier and no amount of comments can adequately explain why it is that way&#8230;. </p>
<p><strong>STOP and back up. You have my permission to code NON-performantly in that situation, if you simply can&#8217;t do so in a reasonably clean or comment-explainable way.</strong> Sheesh, was that so hard? Am I really a crazy lune?</p>
<h3>Summary</h3>
<p>Quit listening to all the negative hype about &#8220;premature optimization&#8221;. It&#8217;s mostly hot air with no substance. It&#8217;s a bunch of developers following what other developers say, mostly blindly. And the few developers who actually have a reason for rallying against &#8220;premature optimization&#8221;, they&#8217;re probably mad about it not because the optimization was <em>premature</em>, but because it was <em><strong>immature</strong></em>.</p>
<p>So, let&#8217;s all just try to grow up and mature a little bit with how we approach performance-savvy coding. We&#8217;ll all get a lot more quality code written that way.</p>
<div><a class="addthis_button" href="//addthis.com/bookmark.php?v=250" addthis:url='http://blog.getify.com/pre-maturely-optimize-revisited/' addthis:title='&#8220;(pre)Maturely Optimize&#8230;&#8221; revisited '><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/pre-maturely-optimize-revisited/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<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>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>Optimize much?</title>
		<link>http://blog.getify.com/optimize-much/</link>
		<comments>http://blog.getify.com/optimize-much/#comments</comments>
		<pubDate>Thu, 30 Sep 2010 19:55:19 +0000</pubDate>
		<dc:creator>getify</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Performance Optimization]]></category>
		<category><![CDATA[UI Architecture]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://blog.getify.com/?p=528</guid>
		<description><![CDATA[I&#8217;ve had some troubling and challenging thoughts swirling around in my weird brain for the last couple of months, and then two days ago, my good friend and fellow Austin.JavaScript attendee Alex Sexton prodded me with this little jab, which I obviously take light-heartedly and in good spirits. But it definitely has me thinking even [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve had some troubling and challenging thoughts swirling around in my weird brain for the last couple of months, and then two days ago, my good friend and fellow <a href="http://austinjavascript.com">Austin.JavaScript</a> attendee <a href="http://twitter.com/slexaxton">Alex Sexton</a> prodded me with <a href="http://twitter.com/SlexAxton/status/25823282188">this little jab</a>, which I obviously take light-heartedly and in good spirits. But it definitely has me thinking even more. I decided it was time to jot down some of these thoughts.</p>
<p>Thinking about what, you ask? <strong>Optimization</strong>. Is it good or not? Is there such a thing as too much (or, as <em>they</em> say, &#8220;premature&#8221;) optimization? Does it <em>really</em> matter if you cut corners in optimization when in the real world, few if any ever notice the difference? &#8220;If a tree falls in the forest and noone is around to hear it&#8230;.&#8221;</p>
<p>It&#8217;s certainly no secret that I&#8217;m a complete performance optimization nerd. I consider myself a Padawan learner under the likes of the incomparable <a href="http://stevesouders.org">Steve Souders</a>. And just look at projects like <a href="http://labjs.com">LABjs (&#8220;the performance script loader&#8221;)</a> and <a href="http://2static.it">2static.it (cookie-less static resource loading)</a>, and you&#8217;ll see that I spend a lot of my time <del>thinking</del> <strong>obsessing</strong> about these topics. </p>
<p>And they are not simple topics to ponder. In fact, they are quite complex. It&#8217;s not quite as easy as just comparing the &#8220;big-O&#8221; notation of two algorithms and declaring one to be the winner, as we were so fond of doing in CS 101. Survey the 40-something rules in <a href="http://developer.yahoo.com/yslow/">YSlow</a> and <a href="http://code.google.com/speed/page-speed/docs/rules_intro.html">PageSpeed</a> and you&#8217;ll see that many of them are contradictory! And that&#8217;s just the tip of the iceberg. Start considering the tradeoffs you make in your code when deciding how to write your for-loops, etc. There&#8217;s a <strong>lot</strong> to think about and balance. </p>
<p><strong>Yeah, we&#8217;ve all got a long way to go at artfully balancing what we optimize and how we optimize it.</strong></p>
<h3>Duck for cover!</h3>
<p>I take a lot of flak (both the fun kind and the not-fun kind) for being so obsessed with all facets of web performance optimization. But I can&#8217;t really help that it&#8217;s kind of default in the way that I think. I am, as the <a href="http://en.oreilly.com/velocity2010">Velocity Conference</a> so keenly states, a &#8220;Fast By Default&#8221; kind of developer. Very little bugs the beegeezus out of me more than seeing (or worse, experiencing) poorly performing code, especially when it&#8217;s so easy to at least <em>start</em> addressing such issues.</p>
<p>I&#8217;m not going to go into details on all the various ways that you can look at addressing the performance of code and architecture (that&#8217;s the stuff of many a book). But know that I&#8217;m talking about both the small things and the big things. This is both a macro-topic and a micro-topic. </p>
<p>It&#8217;s an issue of how your code performs vs. how your code is maintained. But it&#8217;s also an issue of how important is it if your resources are not properly being cached vs. meeting a tight customer deadline to take heat off the boss&#8217; neck. Like I said, these are weighty topics with no clear answers, and many many different factors weighing in.</p>
<p>For better or worse, I often find myself in the minority opinion on such topics, arguing for the principle of efficiency and performance even if the gains are not as <em><strong>directly</strong></em> measurable or tangible. And I understand why many who feel opposite of me feel the way they do.</p>
<p>I work in those same <strong>pragmatic</strong> job environments where the release deadlines are of utmost importance, and the extra 200ms that an inefficient n<sup>2</sup> search algorithm takes are not something anyone around me cares to spend an extra day addressing.</p>
<p>In a recent informal technology-related gathering, one such conversation sparked to life, and as usual, I found myself playing the devil (or devil&#8217;s advocate, depending on your perspective) and really trying to prod at the topic of whether or not coding with optimization as primary motivator (at the expense sometimes of code readability) was a valid approach to take.</p>
<p>The specific topic was <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach">Array.forEach()</a> vs doing a regular for-loop and manually iterating an array&#8217;s elements. But I&#8217;m not here to re-hash that whole conversation. The outcome of the conversation is what was more impactful to me.</p>
<h3>&#8230;or give me death!</h3>
<p>I was arguing that even though the performance gains of the native for-loop might only equal a few <strong>ms</strong> at best (for most real-world data sets) over the Array.forEach syntax (function call overhead, blah blah), the fact that it was more efficient was sufficient justification (without any tangible measurability) over the tradeoff of more complicated (less syntactically &#8220;pretty&#8221;) code. In fact, I believed then, and still do, that the pattern of writing efficient code pays off in the long run by all those little gains adding up.</p>
<p>One astute member of the group quipped &#8220;you&#8217;ll never die by a thousand paper cuts&#8221; because &#8220;you never get all the cuts at once&#8221;. In other words, if I save those few <strong>ms</strong> there, and even in 15 other places in my code, I still will not get enough gains to even be measureable or a performance <em>problem</em> worth addressing. </p>
<p>As this logic goes, the likelihood of having enough of those bad patterns all conspire at the same time to drag down the performance to a noticeable 200ms is so low that it&#8217;s not really a useful developer pattern (at least for the <em>common man developer</em>). &#8220;Let framework developers and JavaScript engine designers worry about such &#8216;weeds&#8217; and just stick to the main path.&#8221;</p>
<p>Let me get right to the my point in recounting this interchange (because it&#8217;s really <strong>not</strong> to re-visit this specific topic, but the overall lessons gleaned).</p>
<p><strong>It&#8217;s not death-by-a-thousand-paper-cuts that worries me. It&#8217;s death by the 900 paper-cuts you don&#8217;t know about and have never thought about before.</strong></p>
<p>This post, more than anything, is an advocacy plea for starting to really <em>think</em> about performance issues more indepth. What concerns me from my plethora of jobs in this industry so far in my young career is how wide-spread the apathy is to such issues. If we never think about such things, we&#8217;ll never be prepared properly to handle the ones that really do matter, especially when faced with a crisis requiring fast and decisive action to address the mess.</p>
<h3>Learned</h3>
<p>I did actually come away from that (and many other) conversations with a more complete picture of how to think about such balancing acts, and the value of tempering principles with pragmatics.</p>
<p>But I still hold fast to this ethos in my own development career: <strong>It is better to err on the side of more performant than on the side of less performant.</strong></p>
<p>I know that not every minute performance optimization is going to be worth the uglier code. In fact, a lot won&#8217;t be &#8220;worth it&#8221;. It&#8217;s quite likely that I will &#8220;over&#8221; (or &#8220;prematurely&#8221;) optimize in my code. But that&#8217;s not going to cause more starving children in Ethiopia. It&#8217;s gonna make my code a little harder to maintain, perhaps, though I can help that with good comments.</p>
<p>But I&#8217;d rather write with a default attitude of attacking problems in the performant way, and then when allowed to refactor, find specific areas to simplify, than the other way around. I believe it&#8217;s far easier, and less risky, to refactor from more performant code to less performant code, than the other way around. I know a lot of people will disagree with that statement. But I truly believe it.</p>
<p>Overall, here&#8217;s my takeaway to leave you with: <strong>The TCO (total-cost-of-ownership) on non-performant code/architecture is much higher than on performant code/architecture.</strong></p>
<p>If you invest those pains little-by-little as you write code (but doing so in a judicious and balanced manner), you will <em>spend</em> less (time, money, etc) in the long run. You trade the short term pains for the long term payoffs. That&#8217;s a time-honored and tested set of wisdom, and I think it would behoove a lot of us to apply that to our jobs a little more often than we currently do.</p>
<div><a class="addthis_button" href="//addthis.com/bookmark.php?v=250" addthis:url='http://blog.getify.com/optimize-much/' addthis:title='Optimize much? '><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/optimize-much/feed/</wfw:commentRss>
		<slash:comments>3</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:49:30 -->
