<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.yuiblog.com/~d/styles/itemcontent.css"?><rss 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/" version="2.0">

<channel>
	<title>Yahoo! User Interface Blog (YUIBlog) » Performance</title>
	
	<link>http://www.yuiblog.com/blog</link>
	<description>The official blog of the YUI Project.</description>
	<lastBuildDate>Thu, 02 Sep 2010 15:16:04 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.yuiblog.com/yuiblog/performance" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="yuiblog/performance" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Mobile Browser Cache Limits, Revisited</title>
		<link>http://www.yuiblog.com/blog/2010/07/12/mobile-browser-cache-limits-revisited/</link>
		<comments>http://www.yuiblog.com/blog/2010/07/12/mobile-browser-cache-limits-revisited/#comments</comments>
		<pubDate>Mon, 12 Jul 2010 16:45:09 +0000</pubDate>
		<dc:creator>Ryan Grove</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://www.yuiblog.com/blog/?p=2316</guid>
		<description><![CDATA[
In Mobile Browser Cache Limits: Android, iOS, and webOS, I shared the results of my attempts to determine browser cache limits on Android, iOS, and webOS devices. At the end of the article, I wrote:

Use these results as a starting point, but verify them yourself before you make major decisions based on assumptions about mobile [...]]]></description>
			<content:encoded><![CDATA[<p>
In <a href="http://www.yuiblog.com/blog/2010/06/28/mobile-browser-cache-limits/">Mobile Browser Cache Limits: Android, iOS, and webOS</a>, I shared the results of my attempts to determine browser cache limits on Android, iOS, and webOS devices. At the end of the article, I wrote:
</p>
<blockquote cite="http://www.yuiblog.com/blog/2010/06/28/mobile-browser-cache-limits/"><p style="margin:0">Use these results as a starting point, but verify them yourself before you make major decisions based on assumptions about mobile cache limitations. The mobile browser world changes at a lightning pace, so this research will have a very short shelf life.</p>
</blockquote>
<p>
As it turns out, that was good advice: the day after the article was posted, <a href="http://stevesouders.com/">Steve Souders</a> commented that he had run tests using a different methodology that was more representative of a real-world web workflow and had gotten different results.
</p>
<h2>New Methodology</h2>
<p>
My original methodology involved navigating directly to a randomly generated page of a certain size, served with a <code>text/html</code> content type. The results using this methodology were reliably reproducible (except on webOS), but as Steve pointed out, users don&#8217;t navigate directly to CSS and JavaScript files. My assumption that the limits for direct navigation to an HTML resource were the same as the limits for external CSS and JavaScript was incorrect, so even though the results of my tests were valid, they weren&#8217;t widely applicable.
</p>
<p>
Over the course of many IM sessions, several emails, and a couple of phone calls, Steve and I worked out a new testing methodology. I implemented a version of it on top of my <a href="http://github.com/rgrove/cachetest">cache testing framework</a>, then Steve <a href="http://stevesouders.com/tests/cachesize/">implemented a version</a> capable of publishing results to <a href="http://www.browserscope.org/">Browserscope</a>.
</p>
<p>
In the new tests, we load an HTML page that refers to a randomly-generated CSS or JavaScript component of a certain size. Then we navigate to a second HTML page that loads the same component and checks whether or not it was loaded from the cache. To determine whether a component was loaded from the cache, we store a timestamp in a cookie on each request; if the timestamp is updated the second time we load the component, we know the request hit the server, which means the component was not loaded from the cache.
</p>
<h2>New Results</h2>
<p>
We found that <strong>all the mobile browsers we tested had significantly higher cache limits for external resources loaded by a page than they did for an HTML page itself</strong>. This is excellent news for mobile web developers.
</p>
<p>
The table below illustrates our findings:
</p>
<style>
.cachestats { font-size: 12px; }</p>
<p>.cachestats td,
.cachestats th {
  margin: 2px;
  padding: 2px;
  text-align: center;
  font-size:12px !important;
}</p>
<p>.cachestats th {
  background: #efefef;
  font-weight: bold;
  padding: 4px;
}</p>
<p>.cachestats .browser { text-align: left; }
.cachestats .doubtful { background-color: #fff0db; }
.cachestats .no { background-color: #ff5f5f; }
.cachestats .yes { background-color: #b3ffaf; }
</style>
<table class="cachestats">
<caption>
    Table: Mobile browser external resource cache characteristics<br />
  </caption>
<thead>
<tr>
<th>Browser/OS/Device</th>
<th>Single Component Limit</th>
<th>Survives Power Cycle</th>
</tr>
</thead>
<tbody>
<tr>
<td class="browser">Android 2.2 (Nexus One)</td>
<td>2MB</td>
<td class="yes">Yes</td>
</tr>
<tr>
<td class="browser">Mobile Safari, iOS 3.1.3 (1st-gen iPhone)</td>
<td>4MB+</td>
<td class="no">No</td>
</tr>
<tr>
<td class="browser">Mobile Safari, iOS 3.2 (iPad)</td>
<td>4MB+</td>
<td class="no">No</td>
</tr>
<tr>
<td class="browser">Mobile Safari, iOS 4.0 (iPhone 3GS)</td>
<td>4MB+</td>
<td class="no">No</td>
</tr>
<tr>
<td class="browser">Mobile Safari, iOS 4.0 (iPhone 4)</td>
<td>4MB+</td>
<td class="no">No</td>
</tr>
<tr>
<td class="browser">webOS 1.4.1 (Palm Pre Plus)</td>
<td><span style="font-size:16px;line-height:12px">~</span>0.99MB (1,023KB)</td>
<td class="yes">Yes</td>
</tr>
</tbody>
</table>
<p>
Note that 4MB was the largest size we tested, and all the iOS devices cached 4MB components. The actual cache limit for those devices may be larger than 4MB. Also, webOS on the Palm Pre Plus gave consistent results in this test, whereas it had some problems in the previous test.
</p>
<p>
It&#8217;s possible that the much lower limits my previous test showed for HTML components on iOS may indicate the use of a RAM cache for those components, while the much higher limits for CSS/JS components in this test may indicate the use of a disk cache, but this is just conjecture. Android, at least, does appear to use a disk cache in both cases, since its cache survives power cycles.
</p>
<h2>New Recommendations</h2>
<p>
Based on these new results, coupled with the results from my previous tests, I offer the following updated set of recommendations:
</p>
<ul>
<li><strong>Use far-future cache expiration headers.</strong> This will prevent the browser from having to send a conditional GET request.</li>
<li><strong>Try to limit HTML pages to 25.6KB or less</strong> if you want them to be cached, since the previous tests showed that this limit&mdash;imposed by iOS 3.2 on the iPad&mdash;was the lowest HTML resource limit of the devices tested.</li>
<li><strong>Keep CSS and JS components under 1MB.</strong> Of course, 1MB is enormous and your components should be much smaller than this, but don&#8217;t bother splitting a component into separate requests for the sake of cacheability unless its size approaches 1MB.</li>
<li><strong>Consider using the HTML5 application cache</strong> if it&#8217;s important that your components persist in the cache for a long time, or across power cycles.</li>
<li><strong>Do your own testing.</strong> I stressed the importance of this in my previous article and I&#8217;ll stress it again here. Use these results as a starting point, but verify them yourself before you make important decisions based on them.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.yuiblog.com/blog/2010/07/12/mobile-browser-cache-limits-revisited/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Mobile Browser Cache Limits: Android, iOS, and webOS</title>
		<link>http://www.yuiblog.com/blog/2010/06/28/mobile-browser-cache-limits/</link>
		<comments>http://www.yuiblog.com/blog/2010/06/28/mobile-browser-cache-limits/#comments</comments>
		<pubDate>Mon, 28 Jun 2010 16:45:22 +0000</pubDate>
		<dc:creator>Ryan Grove</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://www.yuiblog.com/blog/?p=2295</guid>
		<description><![CDATA[ 
.cachenotes,
.cachestats { font-size: 12px; }
.cachenotes { margin: 0.5em auto 1.5em; }
.cachenotes p { margin: 0 auto 0.4em; }
.cachestats td,
.cachestats th {
  padding: 2px;
  text-align: center;
  font-size:12px !important;
}
.cachestats th {
  background: #efefef;
  font-weight: bold;
}
.cachestats .browser { text-align: left; }
.cachestats .doubtful { background-color: #fff0db; }
.cachestats .no { background-color: #ff5f5f; }
.cachestats .yes [...]]]></description>
			<content:encoded><![CDATA[<style> 
.cachenotes,
.cachestats { font-size: 12px; }</p>
<p>.cachenotes { margin: 0.5em auto 1.5em; }
.cachenotes p { margin: 0 auto 0.4em; }</p>
<p>.cachestats td,
.cachestats th {
  padding: 2px;
  text-align: center;
  font-size:12px !important;
}</p>
<p>.cachestats th {
  background: #efefef;
  font-weight: bold;
}</p>
<p>.cachestats .browser { text-align: left; }
.cachestats .doubtful { background-color: #fff0db; }
.cachestats .no { background-color: #ff5f5f; }
.cachestats .yes { background-color: #b3ffaf; }
</style>
<p style="border:1px solid #cfcfcf;padding:6px;background:#f5f5f5;">
<strong>Update (July 12, 2010):</strong> While the results described in this article are accurate for HTML pages, new tests have revealed very different cache limits for CSS and JS resources. The updated results are described in <a href="http://www.yuiblog.com/blog/2010/07/12/mobile-browser-cache-limits-revisited/">Mobile Browser Cache Limits, Revisited</a>.
</p>
<p>
	In early 2008, Wayne Shea and Tenni Theurer wrote a YUI Blog post on <a href="http://www.yuiblog.com/blog/2008/02/06/iphone-cacheability/">iPhone Cacheability</a> in which they shared the results of research into various characteristics and limitations of Mobile Safari&#8217;s cache in iPhone OS 1.x. Among other things, they found that individual components larger than 25KB were not cached, and that there was a maximum total cache size of between 475KB and 500KB.
</p>
<p>
	Much has changed since then. We&#8217;ve seen two new major releases and many minor releases of the iPhone OS (now iOS), and several other mobile devices with highly capable browsers have appeared to challenge the iPhone. Stoyan Stefanov found, in late 2009, that <a href="http://www.phpied.com/iphone-caching/">the iPhone&#8217;s cache limits had changed</a> (sadly, for the worse). But where do things stand now? And what about those non-iOS browsers?
</p>
<h2 id="cache-background">
	Background<br />
</h2>
<p>
	Browsers have two types of caches that we&#8217;re concerned with for the purposes of these tests:
</p>
<ul>
<li>The <strong>component cache</strong>, or object cache, stores individual files. HTML, CSS, JavaScript, and images all go into the component cache. Whenever it needs one of these components, the browser first checks the cache before making a network request.
	</li>
<li>The <strong>page cache</strong>, also known as the back/forward cache, stores an entire page and all of its components, as well as their current state. When you use the back or forward button, the browser will load the page from the page cache if possible.
	</li>
</ul>
<p>
	The <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/offline.html">HTML5 application cache</a> is another type of cache that&#8217;s widely supported by mobile browsers. Browser makers already do a good job of documenting the limits of the application cache, so I didn&#8217;t include it in my testing. More on the application cache later.
</p>
<h2 id="cache-devices-tested">
	Devices Tested<br />
</h2>
<p>
	I tested the following mobile browser/platform combinations:
</p>
<ul>
<li>Android 2.1 (Nexus One)
	</li>
<li>Mobile Safari on iOS 3.1.3 (1st-gen iPhone)
	</li>
<li>Mobile Safari on iOS 3.2 (iPad)
	</li>
<li>Mobile Safari on iOS 4.0 (iPhone 3GS)
	</li>
<li>Mobile Safari on iOS 4.0 (iPhone 4)
	</li>
<li>webOS 1.4.1 (Palm Pre Plus)
	</li>
</ul>
<p>
	<strong>Note:</strong> With the exception of Mobile Safari on iOS 4.0, I tested only one device in each category. If there are variations between individual devices or differences based on installed software beyond the OS, my tests would not detect those variations. These particular devices were tested because they&#8217;re the ones I had access to, not because I consider them to be more important than other devices.
</p>
<h2 id="cache-methodology">
	Methodology<br />
</h2>
<p>
	Cache testing is tedious, but relatively simple.
</p>
<p>
	I wrote a tiny Sinatra app (<a href="http://github.com/rgrove/cachetest">fork it on GitHub!</a>) that generates a response consisting of a requested number of pseudorandom alphanumeric and whitespace bytes. The responses can be served either gzipped or uncompressed. The following far-future expiration response headers are sent to ensure that all responses are considered cacheable:
</p>
<pre>
Cache-Control: max-age=315360000
Expires: Fri, 01 May 2020 03:47:24 GMT
</pre>
<p>
	Over my local network, I then manually performed the following steps on each device to test the component cache:
</p>
<ol>
<li>Load the cache test index page.
	</li>
<li>Tap on a link to a component of a particular size, ranging from 5KB to 20MB, and wait for it to finish loading.
	</li>
<li>Tap the back button.
	</li>
<li>Tap the same link again. Observe whether the random characters are the same, and whether the server console prints a log entry for a request, to determine whether the component was cached in step 2.
	</li>
<li>Repeat and adjust component sizes as necessary to determine the maximum component size that will be cached.
	</li>
</ol>
<p>
	To test the page cache, I performed essentially the same steps except that instead of tapping the link again in step 4, I tapped the browser&#8217;s forward button, causing it to use the page cache rather than the component cache.
</p>
<p>
	Support for <code>ETag</code> and <code>Last-Modified</code> was determined by tweaking the server to send the appropriate <code>ETag</code> or <code>Last-Modified</code> response headers (in separate tests) and to omit the far-future expiration headers. I then inspected the request headers received by the server to verify that the browser sent the expected <code>If-None-Match</code> or <code>If-Modified-Since</code> headers on step 4.
</p>
<h2 id="cache-results">
	Results<br />
</h2>
<p>
	I tested with gzip both enabled and disabled, but I found that <strong>gzip had no effect on cacheability on any device</strong>. The uncompressed component size is what matters in all cases, regardless of whether or not that component is served gzipped. As such, all component sizes mentioned here are uncompressed sizes.
</p>
<p>
	The table below illustrates my overall findings.
</p>
<table class="cachestats">
<caption>
		Table: Mobile browser cache characteristics<br />
	</caption>
<thead>
<tr>
<th>
				Browser/OS/Device
			</th>
<th>
				Single Component Limit
			</th>
<th>
				Total Component Limit
			</th>
<th>
				Page Cache Size Limit
			</th>
<th>
				Supports Last-Modified
			</th>
<th>
				Supports ETag
			</th>
<th>
				Survives Power Cycle
			</th>
</tr>
</thead>
<tbody>
<tr>
<td class="browser">
				Android 2.1 (Nexus One)
			</td>
<td>
				~2MB (~2,048,000b)
			</td>
<td>
				~2MB (~2,048,000b)
			</td>
<td>
				∞ <sup>2</sup>
			</td>
<td class="yes">
				Yes
			</td>
<td class="yes">
				Yes
			</td>
<td class="yes">
				Yes
			</td>
</tr>
<tr>
<td class="browser">
				Mobile Safari, iOS 3.1.3 (1st-gen iPhone)
			</td>
<td>
				0b <sup>1</sup>
			</td>
<td>
				0b <sup>1</sup>
			</td>
<td>
				∞ <sup>2</sup>
			</td>
<td class="no">
				No
			</td>
<td class="no">
				No
			</td>
<td class="no">
				No
			</td>
</tr>
<tr>
<td class="browser">
				Mobile Safari, iOS 3.2 (iPad)
			</td>
<td>
				25.6KB (26,214b)
			</td>
<td>
				~281.6KB (~288,354b)
			</td>
<td>
				25.6KB (26,214b)
			</td>
<td class="yes">
				Yes
			</td>
<td class="yes">
				Yes
			</td>
<td class="no">
				No
			</td>
</tr>
<tr>
<td class="browser">
				Mobile Safari, iOS 4.0 (iPhone 3GS)
			</td>
<td>
				51.199KB (52,428b)
			</td>
<td>
				~1.05MB (~1,100,988b)
			</td>
<td>
				∞ <sup>2</sup>
			</td>
<td class="yes">
				Yes
			</td>
<td class="yes">
				Yes
			</td>
<td class="no">
				No
			</td>
</tr>
<tr>
<td class="browser">
				Mobile Safari, iOS 4.0 (iPhone 4)
			</td>
<td>
				102.399KB (104,857b)
			</td>
<td>
				~1.9MB (~1,992,283b)
			</td>
<td>
				∞ <sup>2</sup>
			</td>
<td class="yes">
				Yes
			</td>
<td class="yes">
				Yes
			</td>
<td class="no">
				No
			</td>
</tr>
<tr class="doubtful">
<td class="browser">
				webOS 1.4.1 (Palm Pre Plus) <sup>3</sup>
			</td>
<td>
				~1MB (~1,048,576)
			</td>
<td>
				?
			</td>
<td>
				~1MB (~1,048,576)
			</td>
<td class="no">
				No
			</td>
<td class="no">
				No
			</td>
<td class="yes">
				Yes
			</td>
</tr>
</tbody>
</table>
<div class="cachenotes">
<p>
		<strong>Notes:</strong>
	</p>
<p>
		<sup>1</sup> Mobile Safari on iOS 3.1.3 doesn&#8217;t appear to cache <em>any</em> components, regardless of size, except for the page cache. It&#8217;s unclear whether this is intentional or a bug.
	</p>
<p>
		<sup>2</sup> The page caches in Android 2.1, iOS 3.1.3, and iOS 4.0 (but not iOS 3.2) appear to be limited only by available RAM when it comes to individual page size. I didn&#8217;t attempt to determine exactly how many separate pages could coexist in the page cache at once.
	</p>
<p>
		<sup>3</sup> webOS test results were inconsistent and at various points the cache seemed to stop working altogether until the phone was power-cycled. I don&#8217;t consider these results conclusive, or even trustworthy, but they&#8217;re listed here for the sake of comparison.
	</p>
</div>
<h3>
	Android<br />
</h3>
<p>
	The Android browser exhibited the best cache behavior of all devices tested. While it appears to impose no limit on the size of individual components, the total cache size seems to be limited to approximately 2MB, which means that individual components are effectively limited to 2MB as well.
</p>
<p>
	The page cache appeared to impose no limit on the size of individual pages, happily caching every byte I threw at it until the available RAM was exhausted and the browser crashed.
</p>
<p>
	I was pleasantly surprised to find that Android&#8217;s component cache survived both browser restarts and power cycles, a feat none of the iOS devices was able to match.
</p>
<p>
	<strong>Possible caveat:</strong> A review of <a href="http://android.git.kernel.org/?p=platform/external/webkit.git;a=summary">Android&#8217;s WebKit source tree</a> leads me to believe that its cache limits may adapt based on the amount of RAM and/or flash memory available on the particular device on which it&#8217;s running. If true, these numbers may only be applicable to the Nexus One. In fact, if the cache size adapts based on unused memory rather than total memory, these numbers may only be applicable to <em>my</em> Nexus One.
</p>
<p>
	I could be mistaken, but the differences in the iOS 4.0 test results on the iPhone 3GS and iPhone 4 support this theory. (Android and Mobile Safari are both WebKit-based browsers, so they may have this behavior in common.) If you&#8217;re familiar with the WebKit source and can shed more light on this, please get in touch with me.
</p>
<h3>
	iOS<br />
</h3>
<p>
	Results varied wildly across the three most recent versions of iOS. Astonishingly, <strong>Mobile Safari on iOS 3.1.3 did not cache components of any size</strong>, despite having an apparently unlimited page cache size. This is troubling since it means iOS 3.1.3 users are likely getting a suboptimal browsing experience, especially if they aren&#8217;t using wifi. The unlimited page cache size does little good here, since it only comes into play for back/forward navigations. This behavior is a significant change from what others observed in previous iOS releases and I can&#8217;t imagine any good reason for it, so I suspect this may be a bug.
</p>
<p>
	Mobile Safari on iOS 3.2 (which is only available on the iPad) does not exhibit this bug. Its 25.6KB component limit and ~281.6KB total cache limit are better than nothing, but they still seem paltry compared to the other devices tested. Uniquely among iOS devices, the iPad appears to limit the size of pages in the page cache to 25.6KB, the same as its component size limit.
</p>
<p>
	Mobile Safari on iOS 4.0 exhibited different limits on the iPhone 3GS and on the iPhone 4, which implies that the limits adapt based on available RAM (the iPhone 3GS has 256MB while the iPhone 4 has 512MB; both devices tested had 32GB of flash memory). On the iPhone 3GS, iOS 4.0 has a 51.199KB component size limit and a ~1.05MB total component cache size.
</p>
<p>
	On the iPhone 4, the component size limit was almost exactly two times the limit on the iPhone 3GS, at 102.399KB. The total component cache size was approximately 1.9MB. Perhaps because iOS 3.2 and iOS 4.0 were developed separately but branched from a common ancestor, the iOS 4.0 page cache size appears to be limited only by available RAM on both devices tested, just like iOS 3.1.3.
</p>
<p>
	None of the iOS devices preserved the contents of the cache across forced browser restarts or device power cycles, although they did preserve the cache when merely switching applications without actually killing the browser.
</p>
<h3>
	webOS<br />
</h3>
<p>
	My test results on webOS were so inconsistent that I have little confidence in them. I&#8217;ve included what little data I managed to gather purely for the sake of completeness. Please take it with a hefty grain of salt.
</p>
<p>
	As near as I was able to determine, webOS <em>might</em> have an individual component size limit of about 1MB, with a matching page size limit in the page cache. I was unable to coax <code>If-None-Match</code> or <code>If-Modified-Since</code> request headers from webOS, which implies that it does not support <code>ETag</code> and <code>Last-Modified</code>.
</p>
<p>
	On some tests, it appeared that webOS&#8217;s maximum component size was greater than 1MB, but this was inconsistent. As far as I can tell, webOS appears to have a nasty bug where, after a certain point—possibly when the maximum total cache size is reached—the cache just completely stops working altogether until the phone is power-cycled. In some cases even power cycling didn&#8217;t fix the cache breakage, so I eventually gave up trying to establish the exact cause of the problem and the exact limits of the webOS cache.
</p>
<h2>
	Recommendations<br />
</h2>
<p>
	Based on these results, I offer the following recommendations to anyone developing web applications for the tested devices:
</p>
<ul>
<li>
		<strong>Use far-future cache expiration headers.</strong> This will prevent the browser from having to send a conditional GET request and will improve cacheability in webOS, which doesn&#8217;t support <code>ETag</code> or <code>Last-Modified</code>.
	</li>
<li>At least until iOS 4.0 arrives on the iPad, try to <strong>limit individual component sizes to 25.6KB or less</strong>, uncompressed. And urge your iPhone users to upgrade to iOS 4.0 as soon as possible.
	</li>
<li>If your website must support iOS 3.1.3 users (which is likely), if it requires components larger than 25.6KB, or if the total size of all your components is larger than 281.6KB, <strong>consider using the HTML5 application cache</strong>, <a href="http://www.w3.org/TR/webstorage/">localStorage</a>, or <a href="http://www.w3.org/TR/offline-webapps/#sql">database storage</a> to store your components. Alex Kessinger&#8217;s recent YUI Blog post, <a href="http://www.yuiblog.com/blog/2010/05/27/yui3-intro-to-offline/">An Introduction to Using YUI 3 in Offline Applications</a>, might be of interest for YUI 3 developers considering this approach.
	</li>
<li>
		<strong>Do your own testing.</strong> Don&#8217;t assume that these results apply to any future version of any of the tested browsers or devices. Use these results as a starting point, but verify them yourself before you make major decisions based on assumptions about mobile cache limitations. The mobile browser world changes at a lightning pace, so this research will have a very short shelf life.
	</li>
</ul>
<p>
	I&#8217;ve <a href="http://github.com/rgrove/cachetest">made my test code available on GitHub</a> and I encourage you to use it, fork it, and share what you learn.
</p>
<h2 id="cache-documentation">
	Call for Documentation<br />
</h2>
<p>
	Browser makers, please consider documenting and publishing your browser&#8217;s cache limits. In the desktop world where these limits are typically so high as to be a non-issue, documentation wasn&#8217;t needed. In the mobile world, browser cache limits are vital information that web developers must have in order to create performant websites with compelling features.
</p>
<p>
	The limits of new features like localStorage and the application cache are typically well-documented. Please extend this level of documentation to the component cache as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yuiblog.com/blog/2010/06/28/mobile-browser-cache-limits/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>YUI Theater — Douglas Crockford: "Ajax Performance"</title>
		<link>http://www.yuiblog.com/blog/2008/12/23/video-crockford-performance/</link>
		<comments>http://www.yuiblog.com/blog/2008/12/23/video-crockford-performance/#comments</comments>
		<pubDate>Tue, 23 Dec 2008 16:07:47 +0000</pubDate>
		<dc:creator>Eric Miraglia</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[YUI Theater]]></category>

		<guid isPermaLink="false">http://yuiblog.com/blog/2008/12/23/video-crockford-performance/</guid>
		<description><![CDATA[
Douglas Crockford returns to YUI Theater with another chapter in his evolving lecture series.  This session, &#8220;Ajax Performance,&#8221; debunks common misconceptions about the relationship between JavaScript and performance and gives engineers a core focus for improving the performance of web apps: Reduce the value of n.  Because DOM interactions are generally slow, leveraging [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://video.yahoo.com/watch/4156174/11192533"><img src="http://ericmiraglia.com/assets/crockford-performance2.jpg" width="510" height="306" /></a></p>
<p>Douglas Crockford returns to YUI Theater with another chapter in his evolving lecture series.  This session, &#8220;Ajax Performance,&#8221; debunks common misconceptions about the relationship between JavaScript and performance and gives engineers a core focus for improving the performance of web apps: <em>Reduce the value of </em>n.  Because DOM interactions are generally slow, leveraging Ajax to reduce the number of DOM operations, Douglas argues, is often the most important optmization you can make.  In fact, it usually dwarfs other techniques in terms of its impact on the actual experience of using a website.</p>
<p>This talk joins <a href="http://developer.yahoo.com/yui/theater/">an extensive library of Douglas&#8217;s lectures now available on YUI Theater</a>, including his popular series on JavaScript.</p>
<ul>
<li><a href="http://yuiblog.com/assets/crockford-performance.zip">Slides (zipped PPT)</a></li>
<li><a href="http://ericmiraglia.com/blog/?p=140">Full text transcript of this talk</a></li>
</ul>
<p><object width="512" height="322"><param name="movie" value="http://d.yimg.com/static.video.yahoo.com/yep/YV_YEP.swf?ver=2.2.30" /><param name="allowFullScreen" value="true" /><param name="AllowScriptAccess" VALUE="always" /><param name="bgcolor" value="#000000" /><param name="flashVars" value="id=11157560&#038;vid=4141759&#038;lang=en-us&#038;intl=us&#038;thumbUrl=http%3A//us.i1.yimg.com/us.yimg.com/p/i/bcst/videosearch/6543/76907810.jpeg&#038;embed=1" /><embed src="http://d.yimg.com/static.video.yahoo.com/yep/YV_YEP.swf?ver=2.2.30" type="application/x-shockwave-flash" width="512" height="322" allowFullScreen="true" AllowScriptAccess="always" bgcolor="#000000" flashVars="id=11157560&#038;vid=4141759&#038;lang=en-us&#038;intl=us&#038;thumbUrl=http%3A//us.i1.yimg.com/us.yimg.com/p/i/bcst/videosearch/6543/76907810.jpeg&#038;embed=1" ></embed></object></p>
<p><a href="http://video.yahoo.com/watch/4141759/11157560">Douglas Crockford: &quot;Ajax Performance&quot;</a> @ <a href="http://video.yahoo.com" >Yahoo! Video</a></p>
<p><img src="http://us.i1.yimg.com/us.yimg.com/i/nt/ic/ut/bsc/vidcam12_1.gif" border="0" hspace="10"><a href="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/crockford-performance.m4v">download (m4v)</a></p>
<h3>In Case You Missed&#8230;</h3>
<p>Some other recent videos from the <a href="http://developer.yahoo.com/yui/theater/">YUI Theater series</a>:</p>
<ul>
<li><strong>Nicole Sullivan:</strong> &quot;Design Fast Websites (Don&#8217;t Blame the Rounded Corners)&quot; (<a href="http://video.yahoo.com/watch/4156174/11192533">Yahoo! Video</a> | <a href="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/sullivan-fast.m4v">.m4v download</a>)</li>
<li><strong>Todd Kloots:</strong> &#8220;Developing Accessible Widgets Using ARIA&#8221; (<a href="http://video.yahoo.com/watch/4073211/10996186">Yahoo! Video</a> | <a href="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/kloots-aria.m4v">.m4v download</a>)</li>
<li><strong>Nicholas C. Zakas:</strong> &quot;Test-Driven Development with YUI Test&quot; (<a href="http://video.yahoo.com/watch/3737228/10267335">Yahoo! Video</a> | <a href="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/zakas-yuitest.m4v">.m4v download</a>)</li>
<li><strong>Douglas Crockford:</strong> &quot;Web Forward&quot; (<a href="http://video.yahoo.com/watch/3730137/10250950">Yahoo! Video</a> | <a href="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/crockford-webforward.m4v">.m4v download</a>)</li>
</ul>
<h3>Subscribing to YUI Theater:</h3>
<ul>
<li><a href="http://feeds.feedburner.com/yuiblog/yui-theater">YUI Theater RSS feed</a></li>
<li><a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewPodcast?id=263846173&amp;s=143441">YUI Theater on iTunes</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.yuiblog.com/blog/2008/12/23/video-crockford-performance/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
<enclosure url="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/crockford-performance.m4v" length="195027943" type="video/x-m4v" />
<enclosure url="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/sullivan-fast.m4v" length="173150421" type="video/x-m4v" />
<enclosure url="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/kloots-aria.m4v" length="123775849" type="video/x-m4v" />
<enclosure url="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/zakas-yuitest.m4v" length="149378402" type="video/x-m4v" />
<enclosure url="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/crockford-webforward.m4v" length="144845803" type="video/x-m4v" />
		</item>
		<item>
		<title>YUI Theater — Nicole Sullivan: "Design Fast Websites (Don’t Blame the Rounded Corners)"</title>
		<link>http://www.yuiblog.com/blog/2008/12/23/video-sullivan/</link>
		<comments>http://www.yuiblog.com/blog/2008/12/23/video-sullivan/#comments</comments>
		<pubDate>Tue, 23 Dec 2008 16:04:25 +0000</pubDate>
		<dc:creator>Eric Miraglia</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[YUI Theater]]></category>

		<guid isPermaLink="false">http://yuiblog.com/blog/2008/12/23/video-sullivan/</guid>
		<description><![CDATA[
Nicole Sullivan is a website performance specialist and a former member of Yahoo&#8217;s Exceptional Performance Team. She is currently writing a book for O&#8217;Reilly with Stoyan Stefanov on performance optimization and she and Stoyan are the creators of Smushit, an engine for crushing images.
Nicole visited Yahoo last week to do an encore of her &#34;Design [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://video.yahoo.com/watch/4156174/11192533"><img src="http://ericmiraglia.com/assets/sullivan-fast.jpg" width="510" height="290" /></a></p>
<p><a href="http://stubbornella.org">Nicole Sullivan</a> is a website performance specialist and a former member of Yahoo&#8217;s Exceptional Performance Team. She is currently writing a book for O&#8217;Reilly with Stoyan Stefanov on performance optimization and she and Stoyan are the creators of <a href="http://smushit.com">Smushit</a>, an engine for crushing images.</p>
<p>Nicole visited Yahoo last week to do an encore of her &quot;Design Fast Websites&quot; talk in which she outlines a set of practical guidelines for building websites that are supremely fast <em>and</em> visually rich. Her advice is to know your craft, to engage your designers, and to make sure that your collaboration with designers works intelligently in the service of users. She was kind enough to let us record the talk and share it with you here on <a href="http://developer.yahoo.com/yui/theater/">YUI Theater</a>.</p>
<ul>
<li><a href="http://www.slideshare.net/stubbornella/designing-fast-websites-presentation">Slides (on Slideshare)</a></li>
</ul>
<p><object width="512" height="322"><param name="movie" value="http://d.yimg.com/static.video.yahoo.com/yep/YV_YEP.swf?ver=2.2.30" /><param name="allowFullScreen" value="true" /><param name="AllowScriptAccess" VALUE="always" /><param name="bgcolor" value="#000000" /><param name="flashVars" value="id=11192533&#038;vid=4156174&#038;lang=en-us&#038;intl=us&#038;thumbUrl=http%3A//us.i1.yimg.com/us.yimg.com/p/i/bcst/videosearch/6581/77038678.jpeg&#038;embed=1" /><embed src="http://d.yimg.com/static.video.yahoo.com/yep/YV_YEP.swf?ver=2.2.30" type="application/x-shockwave-flash" width="512" height="322" allowFullScreen="true" AllowScriptAccess="always" bgcolor="#000000" flashVars="id=11192533&#038;vid=4156174&#038;lang=en-us&#038;intl=us&#038;thumbUrl=http%3A//us.i1.yimg.com/us.yimg.com/p/i/bcst/videosearch/6581/77038678.jpeg&#038;embed=1" ></embed></object></p>
<p><a href="http://video.yahoo.com/watch/4156174/11192533">Nicole Sullivan: &quot;Design Fast Websites&quot;</a> @ <a href="http://video.yahoo.com" >Yahoo! Video</a></</p>
<p><img src="http://us.i1.yimg.com/us.yimg.com/i/nt/ic/ut/bsc/vidcam12_1.gif" border="0" hspace="10"><a href="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/sullivan-fast.m4v">download (m4v)</a></p>
<h3>In Case You Missed&#8230;</h3>
<p>Some other recent videos from the <a href="http://developer.yahoo.com/yui/theater/">YUI Theater series</a>:</p>
<ul>
<li><strong>Todd Kloots:</strong> &#8220;Developing Accessible Widgets Using ARIA&#8221; (<a href="http://video.yahoo.com/watch/4073211/10996186">Yahoo! Video</a> | <a href="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/kloots-aria.m4v">.m4v download</a>)</li>
<li><strong>Nicholas C. Zakas:</strong> &quot;Test-Driven Development with YUI Test&quot; (<a href="http://video.yahoo.com/watch/3737228/10267335">Yahoo! Video</a> | <a href="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/zakas-yuitest.m4v">.m4v download</a>)</li>
<li><strong>Douglas Crockford:</strong> &quot;Web Forward&quot; (<a href="http://video.yahoo.com/watch/3730137/10250950">Yahoo! Video</a> | <a href="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/crockford-webforward.m4v">.m4v download</a>)</li>
<li><strong>Eric Miraglia and Matt Sweeney:</strong> &quot;YUI3 &mdash; A Look Ahead&quot; (<a href="http://video.yahoo.com/watch/3711767/10207432">Yahoo! Video</a> | <a href="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/miraglia-yui3.m4v">.m4v download</a>)</li>
</ul>
<h3>Subscribing to YUI Theater:</h3>
<ul>
<li><a href="http://feeds.feedburner.com/yuiblog/yui-theater">YUI Theater RSS feed</a></li>
<li><a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewPodcast?id=263846173&amp;s=143441">YUI Theater on iTunes</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.yuiblog.com/blog/2008/12/23/video-sullivan/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
<enclosure url="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/sullivan-fast.m4v" length="173150421" type="video/x-m4v" />
<enclosure url="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/kloots-aria.m4v" length="123775849" type="video/x-m4v" />
<enclosure url="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/zakas-yuitest.m4v" length="149378402" type="video/x-m4v" />
<enclosure url="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/crockford-webforward.m4v" length="144845803" type="video/x-m4v" />
<enclosure url="http://us.dl1.yimg.com/download.yahoo.com/dl/ydn/yui/theater/miraglia-yui3.m4v" length="113033117" type="video/x-m4v" />
		</item>
		<item>
		<title>Image Optimization, Part 5: AlphaImageLoader</title>
		<link>http://www.yuiblog.com/blog/2008/12/08/imageopt-5/</link>
		<comments>http://www.yuiblog.com/blog/2008/12/08/imageopt-5/#comments</comments>
		<pubDate>Mon, 08 Dec 2008 13:48:09 +0000</pubDate>
		<dc:creator>Stoyan Stefanov</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://yuiblog.com/blog/2008/12/08/imageopt-5/</guid>
		<description><![CDATA[

About the Author: Stoyan Stefanov is a Yahoo! web developer working for the Exceptional Performance team and leading the development of the YSlow performance tool. He also an open-source contributor, conference speaker and technical writer: his latest book is called Object-Oriented JavaScript.


This is part 5 in an ongoing series. You can read the other parts [...]]]></description>
			<content:encoded><![CDATA[<div class="interview">
<div class="intro">
<p><img src="http://yuiblog.com/assets/stoyan.jpg" alt="Stoyan Stefanov." align="right" hspace="10" vspace="5"><em><strong>About the Author:</strong><a href="http://www.phpied.com"> Stoyan Stefanov</a> is a Yahoo! web developer working for the <a href="http://developer.yahoo.com/performance/">Exceptional Performance</a> team and leading the development of the <a href="http://developer.yahoo.com/yslow/">YSlow</a> performance tool. He also an open-source contributor, conference speaker and technical writer: his latest book is called <a href="http://www.packtpub.com/object-oriented-javascript-applications-libraries/book">Object-Oriented JavaScript</a>.</em></p>
</div>
</div>
<p><em>This is part 5 in an ongoing series. You can read the other parts here:</em></p>
<ul>
<li><a href="http://yuiblog.com/blog/2008/10/29/imageopt-1/">Image Optimization Part 1: The Importance of Images</a></li>
<li><a href="http://yuiblog.com/blog/2008/11/04/imageopt-2/">Image Optimization Part 2: Selecting the Right File Format</a></li>
<li><a href="http://yuiblog.com/blog/2008/11/14/imageopt-3/">Image Optimization Part 3: Four Steps to File Size Reduction</a></li>
<li><a href="http://yuiblog.com/blog/2008/12/05/imageopt-4/">Image Optimization Part 4: Progressive JPEG&#8230;Hot or Not?</a></li>
</ul>
<p>This installment of the image optimization series is about the IE-proprietary AlphaImageLoader CSS filter, which developers often use as a workaround to solve transparency issues with truecolor PNGs in IE. The problem with AlphaImageLoader is that it hurts page performance and, therefore, hurts user experience.  I argue that AlphaImageLoader should be avoided when at all possible.</p>
<h3>Quick Refresher</h3>
<p>As mentioned in a <a href="http://yuiblog.com/blog/2008/11/04/imageopt-2/">previous article</a>, <a href="http://en.wikipedia.org/wiki/Portable_Network_Graphics">PNGs</a> come in several different types but can roughly be divided into:</p>
<ul>
<li>Indexed (palette), also referred to as PNG8 which have up to 256 colors.</li>
<li>Truecolor PNG, also referred to as PNG32 or PNG24.</li>
</ul>
<p>Both formats support alpha (variable) transparency and, while PNG8 images degrade to a GIF-like non-variable transparency in IE6 (<a href="http://yuiblog.com/assets/png8-transparency.png">example</a>, <a href="http://www.sitepoint.com/blogs/2007/09/18/png8-the-clear-winner/">source</a>), truecolor PNGs show an uglyish background in place of the transparent pixels (source <a href=""http://www.w3.org/Graphics/PNG/inline-alpha.html>W3C</a>).</p>
<p><img src="http://yuiblog.com/assets/png-transparency.png" alt="truecolor PNG transparency problem in IE6" /></p>
<h3>The AlphaImageLoader fix</h3>
<p>IE6 (and older versions of IE) provides a solution to the problem through its proprietary <code>filter</code> CSS property. The following code will display the proper image cross-browser:</p>
<pre>
#some-element {
    background: url(image.png);
    _background: none;
    _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='image.png', sizingMethod='crop');
}
</pre>
<p>As you can see, the underscore CSS hack is used to target IE &lt; 7 and</p>
<ol>
<li>&#8220;undo&#8221; the background; and</li>
<li>load the same image, using Microsoft&#8217;s AlphaImageLoader filter.</li>
</ol>
<p>The reason to target IE prior to version 7 is that IE7 supports the alpha transparency natively without the need for filters. (IE8 does too and it actually <a href="http://blogs.msdn.com/ie/archive/2008/09/08/microsoft-css-vendor-extensions.aspx">changes the filter syntax</a> completely.)</p>
<p>
It&#8217;s interesting to note that the filter doesn&#8217;t change the image; rather, it changes the HTML element this style is applied to. The other interesting thing is that each element is processed synchronously in a single UI thread. The process applying the filter takes some resources for each element and the more &#8220;filtered&#8221; elements you have, the worse it gets, even if you use the same image for all the elements.
</p>
<p>The question is: How does this affect the overall performance of the page?</p>
<h3>Freeze! Side Effect #1</h3>
<p>Here&#8217;s a simple experiment: Create a page that has a CSS filter and then simulate (and exaggerate) network latency by delaying the image used in the filter by ten seconds. The result? Not only is nothing rendered (blank page) for ten seconds, but the browser freezes, meaning you cannot interact with it, click its icons or menus, type in the URL&#8230;you can&#8217;t even close it.</p>
<p><a href="http://yuiblog.com/assets/image-opt-tests/alphatest.html">Here&#8217;s a test example.</a></p>
<p>In the example, I didn&#8217;t use the underscore hack so you can see the (d)effect in IE7 too, even in IE8 in &#8220;compatibility mode&#8221;.</p>
<p>While the effect is exaggerated for demo purposes, network latencies are a fact of life and this is probably the worst user experience you can deliver: Someone comes to your page and their browser freezes.</p>
<p>Note that parallel downloads are not blocked. The browser still downloads the other page components in the background, but there&#8217;s no progressive rendering. You can think of it this way &mdash; since IE will not render anything until the very last bit of CSS comes down the wire (<a href="http://www.phpied.com/rendering-styles/">more info</a>), and your because CSS has a dependency on a filtered image, the rendering is blocked until the dependency is satisfied.</p>
<p>What if you have several AlphaImageLoader filters on the page? They are processed synchronously one after the other so the problem is multiplied. If you have 5 images, each delayed 2 seconds on the server, then the browser freezes for a total of 10 seconds.</p>
<h3>Time and Memory &mdash; Side Effects #2 and #3</h3>
<p>Another negative effect of using the AlphaImageLoader is the increase of the amount of memory required to process and apply the filters. These days we might be tempted to think our visitors&#8217; computers have a virtually indefinite supply of memory, but for older computers (those more likely to run IE6 and under) this may not be the case.</p>
<p>And at the end of it, it&#8217;s the performance we&#8217;re most interested in, performance as measured by the time it takes for the page to load in the browser. Let&#8217;s do a test to measure how much time and memory is required by the filters.</p>
<p>First, let&#8217;s have a baseline page &mdash; one that has a hundred &lt;div&gt;s with the same non-filtered background image. Then let&#8217;s have a second page with a filter applied to the divs (all 100 divs use the same). A hundred elements with filtered backgrounds is unlikely to be found in a normal page, but a little exaggeration will help with the measurements.</p>
<p>The time is measured from the start of the page to the onload event of the page, after the images have been cached, thus eliminating the time required to download the page and the images. The memory consumption is measured with the help of the <a href="http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx">ProcessExplorer</a> tool and given as the before/after delta of the private bytes measurement, showing the &#8220;price&#8221; of rendering the page.
<p>Here are the median results from 10 runs in IE6 on a PC with a dual 2GHz CPU and 500M RAM. On a less powerful computer, the load times are likely to be even worse.</p>
<style type="text/css">td.number{text-align:right}</style>
<table border="1">
<caption>AlphaImageLoader test results</caption>
<tbody>
<tr>
<th>test page</th>
<th>time, seconds</th>
<th>memory, MB</th>
</tr>
<tr>
<td><a href="alpha-no-filter-100.html">Test #1 &#8211; no filters</a></td>
<td class="number">0.031</td>
<td class="number">0.6</td>
</tr>
<tr>
<td><a href="alpha-filter-100.html">Test #2 &#8211; with filters</a></td>
<td class="number">0.844</td>
<td class="number">46.8</td>
</tr>
</tbody>
</table>
<p>As you can see, the AlphaImageLoader effect is pretty bad &mdash; our test page loads 27 times slower and eats up 78 times more memory. These results are, of course, highly speculative &mdash; it&#8217;s just one image tested on just one PC (relatively powerful and underworked). With different images, applied to a different number of elements and on different machines, results may vary considerably, especially when there&#8217;s less RAM or CPU, or if you throw network latency (side effect #1) into the mix. But this example illustrates the important concepts:</p>
<ul>
<li>AlphaImageLoader is slow and requires more memory</li>
<li>It&#8217;s applied per element, not per image</li>
</ul>
<p>If you have a sprite image and you use it for different elements (sprites with alpha filters are trickier, <a href="http://www.julienlecomte.net/blog/2007/07/4/">but doable</a>), you&#8217;ll pay the penalty for each element the sprite is used on.</p>
<h3>Yahoo! Search Case Study</h3>
<p>Using lab tests like the one above can give us some idea of the AlphaImageLoader &#8220;price,&#8221; and you might be tempted to test and calculate approximately how much you pay for each filtered element, but there&#8217;s nothing better than a real life test with millions of requests coming form different parts of the world with different browsers, computers and bandwidth.</p>
<p><a href="http://search.yahoo.com/search?p=yahoo+search">Yahoo!&#8217;s search results page</a> used to have a truecolor PNG sprite and employed AlphaImageLoader to achieve the transparency (an <a href="http://us.js2.yimg.com/us.yimg.com/i/us/sch/el/ngsprt_srp_20071130.png">older version of the sprite</a> is still around if you&#8217;re curious). Replacing the truecolor PNG with a gracefully degrading PNG8 (<a href="http://yuiblog.com/blog/2008/11/04/imageopt-2/">discussed previously</a>) decreased the pageload time by 50-100ms for the users of IE 5 and 6. 100ms may not seem like much, but for a page that loads under a second, it&#8217;s at least 10%. Also, according to <a href="http://home.blarg.net/%7Eglinden/StanfordDataMining.2006-11-29.ppt">an Amazon study</a>, 100ms slower means 1% fewer sales (even for their content-heavy pages). Earning 1% more by just replacing an image doesn&#8217;t look like a bad deal at all.</p>
<h3>So Now What?</h3>
<p>The best thing would be to avoid AlphaImageLoader completely and, like Y!Search, take the time to create PNG8 images that degrade nicely in IE6 and look good in all other browsers. How do you create a gracefully degrading PNG8? Well, create a GIF-like image first, one that has only fully transparent or fully opaque pixels. After making sure it looks acceptable (it will look like this in IE6), proceed to enhancing the image with semi-transparent pixels which will smooth any rounded corners or other parts that would benefit from transparency. Unfortunately, as far as I know, Fireworks is currently the only image processing software capable of handling alpha transparency in PNG8. You can also try command line tools such as <a href="pngnq.sourceforge.net">pngnq</a> and <a href="http://www.libpng.org/pub/png/apps/pngquant.html">pngquant</a>, although automated truecolor-to-palette PNG conversion might not always yield satisfactory results and you might need to pick the fully opaque pixels manually.</p>
<p>There might be cases when you won&#8217;t be able to get by with a PNG8 and absolutely need to use AlphaImageLoader &mdash; for example when most or all pixels are semi-transparent (imagine a &#8220;play&#8221; button over a video thumbnail). Dave Artz of AOL has some <a href="http://www.artzstudio.com/2008/07/png-alpha-transparency-no-clear-winner/">other cases</a> where PNG8 will not be good enough. In such cases (but only after you try your best to persuade the designer to reconsider the use of transparency), make sure you use the underscore hack (<code>_filter</code>) so that you don&#8217;t penalize IE7 users.</p>
<p>Sometimes instead of PNG8 people use GIF for IE6 and truecolor PNG for the others, but that&#8217;s not necessary; with one PNG8 you achieve both binary and alpha transparency.</p>
<p>Additional benefits from using a PNG8 are:</p>
<ol>
<li>PNG8 is usually smaller than truecolor PNG,</li>
<li>only one image to maintain for all browsers</li>
<li>cleaner CSS with no hacks, branches or proprietary tags</li>
<li>ability to repeat background</li>
</ol>
<h3>Transparency with VML</h3>
<p>Using VML is yet another option in IE to make a truecolor PNG transparent, and it solves several problems: alpha transparency, performance, and background repeat. Unfortunatelly, it comes with the price of extra non-standard markup (or dependency on JavaScript to generate it if you want your initial markup clean) and more propritary CSS. Here&#8217;s an example on how to implement it.</p>
<p>If, for example, you have an empty div, you need to wrap it in one VML <code>:rect</code> (or <code>:shape</code>) and one <code>:fill</code> element, like this:</p>
<pre>
&lt;v:rect&gt;
  &lt;v:fill type=&quot;tile&quot; src=&quot;alphatest.png&quot;&gt;
    &lt;div&gt;&amp;nbsp;&lt;/div&gt;
  &lt;/v:fill&gt;
&lt;/v:rect&gt;
</pre>
<p>Somewhere in the markup before that you also need to declare a VML namespace:</p>
<pre>
&lt;xml:namespace ns=&quot;urn:schemas-microsoft-com:vml&quot; prefix=&quot;v&quot; /&gt;
</pre>
<p>And in your stylesheet you need:</p>
<pre>
v\:rect  {
    behavior:url(#default#VML);
    width: 100px;
    height: 100px;
    display: block;
}

v\:fill  {
    behavior:url(#default#VML);
}
</pre>
<p><a href="http://yuiblog.com/assets/image-opt-tests/vml.html">A test page</a> with 100 VML <code>rect</code> elements loads in 0.094 seconds (almost 10 times faster than using filters) and the memory usage is under 4Mb (10 times less than the filtered page).</p>
<p>As you can see this solution adds more markup and proprietary CSS, but it&#8217;s still a solution and doesn&#8217;t have the penalties of the AlphaImageLoader.</p>
<p>(Thanks go to <a href="http://dillerdesign.com/experiment/DD_roundies/">this post</a> by Drew Diller and also <a href="http://www.htmlremix.com/curved-corner-border-radius-cross-browser/">HTML Remix</a>, who accidentally found this side effect while working on another problem  &mdash; rounded corners with VML, via <a href="http://snook.ca/archives/html_and_css/ie-rounded/">snook.ca</a>)</p>
<h3>P.S. &#8230;and What about Other Filters</h3>
<p>AlphaImageLoader is not the only filter that exists. Another popular one is the opacity filter. </p>
<p>For example, for 50% element opacity developers use the properties: </p>
<ul>
<li><code>opacity: 0.5</code> (standard),</li>
<li><code>-moz-opacity: 0.5</code> (early Mozilla versions, before Firefox 0.9), and</li>
<li>for IE, <code>filter: alpha(opacity=50)</code>.</li>
</ul>
<p>A quick test in IE6 shows that the opacity filter is not nearly as slow as the AlphaImageLoader, but it&#8217;s still making the page slower and takes the same amount of memory. This test uses color background, not an image, but even with an image the results are pretty much the same.</p>
<table border="1">
<caption>opacity filter test results</caption>
<tbody>
<tr>
<th>test page</th>
<th>time, seconds</th>
<th>memory, MB</th>
</tr>
<tr>
<td><a href="alpha-no-opacity-100.html">Test #3 &#8211; 100 divs, no opacity</a></td>
<td class="number">0.016</td>
<td class="number">0.2</td>
</tr>
<tr>
<td><a href="alpha-opacity-100.html">Test #4 &#8211; 100 divs with opacity</a></td>
<td class="number">0.093</td>
<td class="number">46.7</td>
</tr>
</tbody>
</table>
]]></content:encoded>
			<wfw:commentRss>http://www.yuiblog.com/blog/2008/12/08/imageopt-5/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Image Optimization, Part 3: Four Steps to File Size Reduction</title>
		<link>http://www.yuiblog.com/blog/2008/11/14/imageopt-3/</link>
		<comments>http://www.yuiblog.com/blog/2008/11/14/imageopt-3/#comments</comments>
		<pubDate>Fri, 14 Nov 2008 16:37:31 +0000</pubDate>
		<dc:creator>Stoyan Stefanov</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://yuiblog.com/blog/2008/11/14/imageopt-3/</guid>
		<description><![CDATA[

About the Author: Stoyan Stefanov is a Yahoo! web developer working for the Exceptional Performance team and leading the development of the YSlow performance tool. He also an open-source contributor, conference speaker and technical writer: his latest book is called Object-Oriented JavaScript.


This is part 3 in an ongoing series. You can read the other parts [...]]]></description>
			<content:encoded><![CDATA[<div class="interview">
<div class="intro">
<p><img src="http://yuiblog.com/assets/stoyan.jpg" alt="Stoyan Stefanov." align="right" hspace="10" vspace="5"><em><strong>About the Author:</strong><a href="http://www.phpied.com"> Stoyan Stefanov</a> is a Yahoo! web developer working for the <a href="http://developer.yahoo.com/performance/">Exceptional Performance</a> team and leading the development of the <a href="http://developer.yahoo.com/yslow/">YSlow</a> performance tool. He also an open-source contributor, conference speaker and technical writer: his latest book is called <a href="http://www.packtpub.com/object-oriented-javascript-applications-libraries/book">Object-Oriented JavaScript</a>.</em></p>
</div>
</div>
<p><em>This is part 3 in an ongoing series. You can read the other parts here:</em></p>
<ul>
<li><a href="http://yuiblog.com/blog/2008/10/29/imageopt-1/">Image Optimization Part 1: The Importance of Images</a></li>
<li><a href="http://yuiblog.com/blog/2008/11/04/imageopt-2/">Image Optimization Part 2: Selecting the Right File Format</a></li>
<li><a href="http://yuiblog.com/blog/2008/12/05/imageopt-4/">Image Optimization Part 4: Progressive JPEG…Hot or Not?</a></li>
</ul>
<p>This post is about some common tools you can use to reduce the file size of your images. The idea is to be able to just take the images your designer has created and instead of using them &#8220;as is&#8221;, go ahead and tidy them up in short time and no effort, without even looking at them.</p>
<p>The good news is that this process is:</p>
<ul>
<li><em>lossless</em> &#8211; you strip bytes, hence you lose some information, but not the pixel data and the resulting image looks exactly the same as the source with no quality loss</li>
<li><em>uses free tools</em> &#8211; all the tools we mention here are free and open-source, and work on both Windows and Unix</li>
<li><em>automated</em> &#8211; since these are command line tools, they are easy to script and automate; one example of such automation is the <a href="http://smush.it">smush.it</a> tool</li>
</ul>
<h3>Step 1: Crush PNG</h3>
<p>PNGs store information in so-called &#8220;chunks&#8221; and not all of those chunks are required for the display of the image. In fact most of them are not. You can safely use a tool such as <a href="http://pmt.sourceforge.net/pngcrush/">pngcrush</a> and strip all the unneeded chunks. For example:</p>
<pre>&gt; pngcrush -rem alla -brute -reduce src.png dest.png</pre>
<p>Let&#8217;s take a look at the options of this command:</p>
<ul>
<li><code>src.png</code> is the source image, <code>dest.png</code> is the destination (result) image</li>
<li><code>-rem alla</code> means remove all chunks but keeps the one for transparency</li>
<li><code>-reduce</code> tries to reduce the number of colors in the palette if this is possible</li>
<li><code>-brute</code> tries over a hundred different methods for optimization in addition to the default 10. It&#8217;s slower and most of the times doesn&#8217;t improve much. But if you&#8217;re doing this process &#8220;offline&#8221;, one or two more seconds are not important since there&#8217;s a chance if a filesize win. Remove this option in performance-sensitive scenarios.</li>
</ul>
<p>Running this command on the PNGs found on Alexa&#8217;s top 10 sites gives us an average file size reduction of <strong>16.05%</strong>. This means you can easily <strong>strip weight off your PNG images</strong>, save bandwidth and disk space and improve load times, without sacrificing quality and without even touching a single line of application code.</p>
<p>PNGcrush is only one of the available tools for this sort of optimizations. Other tools you can take a look at include:
<ul>
<li><a href="http://www.pobox.com/~jason1/pngrewrite/">pngrewrite</a></li>
<li><a href="http://www.cs.toronto.edu/~cosmin/pngtech/optipng/">OptiPNG</a></li>
<li><a href="http://advsys.net/ken/utils.htm">PNGOut</a></li>
</ul>
<p>Now that we&#8217;ve got a pretty good PNG solution, let&#8217;s see if we can do the same for the other image types.</p>
<h3>Step 2: Strip JPG Metadata</h3>
<p>JPEGs files contain meta data such as:
<ul>
<li>comments</li>
<li>application-specific (think Photoshop) meta data</li>
<li>EXIF information such as camera information, date the photo was taken and even thumbnails of the actual image or audio!</li>
</ul>
<p>This meta data is not required for the display of the image and can safely be stripped with no pixel quality loss. As discussed previously, JPEG is a lossy format, which means you lose quality every time you save. But luckily there are some operations that are lossless. Such operations include cropping a part of the image, rotation and the personal favorite &#8211; copying metadata. One tool that allows you to do these is called <a href="http://jpegclub.org/">jpegtran</a>.</p>
<p>Here&#8217;s a command to copy the source image, optimize it and don&#8217;t carry over any metadata in the new copy:</p>
<pre>&gt; jpegtran -copy none -optimize src.jpg dest.jpg</pre>
<p>Note that depending on the version you have, you might need to use the syntax ending with <code>src.jpg &gt; dest.jpg</code></p>
<p>The <code>-optimize</code> option will cause jpegtran to optimize the Huffman tables and improve compression.</p>
<p>Running this command on Alexa top 10 sites resulted in average savings of <strong>11.85%</strong>.</p>
<p>You may be able to further improve image size by using jpegtran&#8217;s <code>-progressive</code> option. It produces JPEGs that load progressively in the browser, starting from a lower quality version of the image and improving as new image information arrives.</p>
<p><strong>Important note on stripping meta information: do it only for images that you own, because when jpegtan strips all the meta, it also strips any copyright information contained in the image file.</strong></p>
<h3>Step 3: GIF to PNG</h3>
<p>What&#8217;s the best way to improve a GIF? Convert it to a PNG. As funny as it may sound, it&#8217;s true. Most of the time you get a smaller file size from a PNG and the same quality and browser support, <a href="http://yuiblog.com/blog/2008/11/04/imageopt-2/">as we discussed in a previous article</a>. Note that PNG will not always be smaller, but most of the time it will be, so it&#8217;s worth checking after the conversion and keeping the smaller of the two files.</p>
<p>In order to automatically change your GIFs, you can use ImageMagick&#8217;s <code>convert</code>:</p>
<pre>&gt; convert image.gif image.png</pre>
<p>If you want to force PNG8 format you can use:</p>
<pre>&gt; convert image.gif PNG8:image.png</pre>
<p>This is probably not necessary, since GIFs will most likely be converted to a PNG8 anyway because ImageMagick picks the appropriate format based on the number of colors.</p>
<p>Once you&#8217;ve converted the GIF to a PNG, don&#8217;t forget to still crush the PNG result (as shown in step 1).</p>
<p>If the top 10 sites switch all their GIFs for PNGs (except those that don&#8217;t yield a smaller file size), on average, this will result in <strong>20.42%</strong> file size reduction. The only inconvenience here is that you also need to write a search/replace script to find all the references to the GIF files and change them to the new PNG versions.</p>
<h3>Step 4: Optimize GIF animations</h3>
<p>Now that all GIFs are PNGs, PNGs are crushed and so are the JPEGs, what do we have left? GIF animations. One tool that can help you with those guys is called <a href="http://www.lcdf.org/gifsicle/">GIFsicle</a>. Since the animations consist of frames and some parts of the image don&#8217;t change from one frame to another, GIFsicle doesn&#8217;t carry over the duplicate pixel information. The way to run it is:</p>
<pre>&gt; gifsicle -O2 src.gif &gt; dest.gif</pre>
<h3>Smush.it</h3>
<p>As we said at the beginning, the beauty of those four steps is that they don&#8217;t cause quality loss, so you don&#8217;t have to open and compare the results before and after. They are also all command-line tools that can be automated easily. So you have nothing to lose by running all your images through those tools before you FTP them to your web server, you can only win.</p>
<p>And you can always try the <a href="http://smush.it">smush.it</a> tool, just to get an idea of how much you can potentially save.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yuiblog.com/blog/2008/11/14/imageopt-3/feed/</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
		<item>
		<title>Image Optimization Part 2: Selecting the Right File Format</title>
		<link>http://www.yuiblog.com/blog/2008/11/04/imageopt-2/</link>
		<comments>http://www.yuiblog.com/blog/2008/11/04/imageopt-2/#comments</comments>
		<pubDate>Tue, 04 Nov 2008 17:16:42 +0000</pubDate>
		<dc:creator>Stoyan Stefanov</dc:creator>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://yuiblog.com/blog/2008/11/04/imageopt-2/</guid>
		<description><![CDATA[

About the Author: Stoyan Stefanov is a Yahoo! web developer working for the Exceptional Performance team and leading the development of the YSlow performance tool. He also an open-source contributor, conference speaker and technical writer: his latest book is called Object-Oriented JavaScript.


This is part 2 in an ongoing series. You can read the other parts [...]]]></description>
			<content:encoded><![CDATA[<div class="interview">
<div class="intro">
<p><img src="http://yuiblog.com/assets/stoyan.jpg" alt="Stoyan Stefanov." align="right" hspace="10" vspace="5"><em><strong>About the Author:</strong><a href="http://www.phpied.com"> Stoyan Stefanov</a> is a Yahoo! web developer working for the <a href="http://developer.yahoo.com/performance/">Exceptional Performance</a> team and leading the development of the <a href="http://developer.yahoo.com/yslow/">YSlow</a> performance tool. He also an open-source contributor, conference speaker and technical writer: his latest book is called <a href="http://www.packtpub.com/object-oriented-javascript-applications-libraries/book">Object-Oriented JavaScript</a>.</em></p>
</div>
</div>
<p><em>This is part 2 in an ongoing series. You can read the other parts here:</em></p>
<ul>
<li><a href="http://yuiblog.com/blog/2008/10/29/imageopt-1/">Image Optimization Part 1: The Importance of Images</a></li>
<li><a href="http://yuiblog.com/blog/2008/11/14/imageopt-3/">Image Optimization Part 3: Four Steps to File Size Reduction</a></li>
<li><a href="http://yuiblog.com/blog/2008/12/05/imageopt-4/">Image Optimization Part 4: Progressive JPEG…Hot or Not?</a></li>
</ul>
<p>This second installment of the image optimization series talks about file formats and how to chose the right one for the job. We&#8217;ll briefly discuss the popular GIF and JPEG formats and then move on to highlighting the rock star, PNG, hopefully helping correct some misconceptions about it.</p>
<h3>GIF</h3>
<p>GIF is a palette (also called &#8220;indexed&#8221;) type of image. It contains a palette of indexed colors, up to 256, and for every pixel of the image there is a corresponding color index. The format is no longer subject to patent issues, so you can create GIFs without the risk of going to jail. (For more on the history of the GIF format, <a href="http://www.cloanto.com/users/mcb/19950127giflzw.html">click here</a>.)</p>
<p>GIF is a <em>non-lossy</em> format, which means that when you modify the image and save it, you don&#8217;t lose quality.</p>
<p>GIF also support animations, which, in the dark Web 1.0 ages, resulted in a plethora of blinking &#8220;new&#8221; images, rotating @ signs, birds dropping &#8230; an email, and other annoyances. In the much more civilized Web 2.0 era, we still have &#8220;loading&#8230;&#8221; animations while we wait for the results of the next Ajax request to update the page, but there are also things like the good old shiny sparkles that people like to put in their social network profiles. Nevertheless, animation support is here if you need it.</p>
<p>GIF also supports transparency, which is a sort of boolean type of transparency. A pixel in a GIF image is either fully transparent or it&#8217;s fully opaque.</p>
<h3>JPEG</h3>
<p>JPEG doesn&#8217;t have the 256 colors restriction associated with GIFs; it can contain millions of colors and it has great compression. This makes it suitable for photos and, in fact, most cameras store photos in JPEG format. It&#8217;s a <em>lossy</em> format, meaning you lose quality with every edit, so it&#8217;s best to store the intermediate results in a different format if you plan to have many edits. There are, however, some operations that can be performed losslessly, such as cropping a part of the image, rotating it or modifying meta information, such as comments stored in the image file.</p>
<p>JPEG doesn&#8217;t support transparency.</p>
<h3>PNG</h3>
<p>PNGs is a <em>non-lossy</em> format that comes in several kinds, but for practical purposes, we can think of PNGs as being of two kinds:</p>
<ol>
<li>PNG8, and</li>
<li>truecolor PNGs.</li>
</ol>
<p>PNG8 is a palette image format, just like GIF, and 8 stands for 8 bits, or 2<sup>8</sup>, or 256, the number of palette entries. The terms &#8220;PNG8&#8243;, &#8220;palette PNG&#8221; and &#8220;indexed PNG&#8221; are used interchangeably. </p>
<p>How does PNG8 compare to GIF?</p>
<ul>
<li>Pros:
<ul>
<li>it usually yields a smaller file size</li>
<li>it supports alpha (variable) transparency</li>
</ul>
</li>
<li>Cons:
<ul>
<li>no animation support</li>
</ul>
</li>
</ul>
<p>The second type of PNGs, truecolor PNGs, can have millions of colors, like JPEG. You can also sometimes come across the names PNG24 or PNG32.</p>
<p>And how does truecolor PNG compare to JPEG? On the pros side, it&#8217;s non-lossy and supports alpha transparency, but on the cons side, the file size is bigger. This makes truecolor PNG an ideal format as an intermediate between several edits of a JPEG and also in cases where every pixel matters and the file size doesn&#8217;t matter much, such as taking screeenshots for a help manual or some printed material.</p>
<h3>Internet Explorer and PNG transparency</h3>
<p>We said that both PNG types support alpha transparency, but there are some browser eccentricities that affect both types and about which you should be aware.</p>
<p>With PNG8, whenever you have semi-transparent pixels they appear as fully transparent in IE (version 6 and lower). This is not ideal but it&#8217;s still useful and is the same behavior that you get from a GIF. So by using a PNG8, in the worst case (IE &lt; 7) you get the same user experience as with a GIF, while for other browsers (Firefox, Safari, Opera) you get a better experience. Below is an example that illustrates this, note how in IE6 the semi-transparent light around the bulb is missing (source: <a href="http://www.sitepoint.com/blogs/2007/09/18/png8-the-clear-winner/">SitePoint</a>):</p>
<p><img src="http://yuiblog.com/assets/png8-transparency.png" alt="PNG8 alpha transparency" /></p>
<p>For truecolor PNGs, the situation is a much less attractive compromise. All the semi transparent pixels appear grey in IE prior to version 7 (source: <a href="http://www.w3.org/Graphics/PNG/inline-alpha.html">W3C</a>).</p>
<p><img src="http://yuiblog.com/assets/png-transparency.png" alt="transparency in truecolor PNG" /></p>
<p>IE7 introduces proper native support for alpha transparency in both PNG8 and truecolor PNGs. For earlier IE versions you need to fix the truecolor PNG transparency issue using CSS and an AlphaImageLoader filter, which we&#8217;ll discuss in more details in a follow-up article. (Spoiler alert: <em>avoid AlphaImageLoader</em>.)</p>
<h3>&#8220;All we are saying is: Give PiNG a chance!&#8221;</h3>
<p>Although PNG8 should be the preferred of the PNGs, because it&#8217;s smaller in filesize and degrades well in early IEs without special CSS filters, there are still some use cases for truecolor PNGs:</p>
<ul>
<li><strong>When the 256 colors of the PNG8 are not enough, you may need a truecolor PNG.</strong> This is a case you should try to avoid. On one hand, if you have thousands and thousands of colors, this starts to look like a case where JPEG will be better suited and will give better compression. On the other hand, if the colors are around a thousand or so, you may try to convert this image to a PNG8 and see if it looks acceptable. Very often, the human eye is not sensitive enough to tell the difference between 200 and 1000 colors. That depends on the image, of course; often you can safely remove 1000 colors, but sometimes removing even 2 colors results in an unacceptable image. In any event, try your potential truecolor PNG candidate as PNG8 and as JPEG and see if you like the result in terms of quality and file size.</li>
<li><strong>When most of the image is semi-transparent.</strong> If only a small part of the image is semi-transparent, like around rounded corners, the GIF-like degradation of PNG8 is often OK. But if most of the image is translucent (think a PLAY button over a video thumbnail), you might not have a choice but to use the AlphaImageLoader hack.</li>
</ul>
<p>At the end, let&#8217;s summarize what was discussed in this article highlighting that:</p>
<ul>
<li>JPEG is the format for photos.</li>
<li>GIF is the format for animations.</li>
<li>PNG8 is the format for everything else &mdash; icons, buttons, backgrounds, graphs&#8230;you name it.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.yuiblog.com/blog/2008/11/04/imageopt-2/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>Image Optimization Part 1: The Importance of Images</title>
		<link>http://www.yuiblog.com/blog/2008/10/29/imageopt-1/</link>
		<comments>http://www.yuiblog.com/blog/2008/10/29/imageopt-1/#comments</comments>
		<pubDate>Wed, 29 Oct 2008 20:28:35 +0000</pubDate>
		<dc:creator>Stoyan Stefanov</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://yuiblog.com/blog/2008/10/29/imageopt-1/</guid>
		<description><![CDATA[

About the Author: Stoyan Stefanov is a Yahoo! web developer working for the Exceptional Performance team and leading the development of the YSlow performance tool. He also an open-source contributor, conference speaker and technical writer: his latest book is called Object-Oriented JavaScript.


This is part 1 in an ongoing series. You can read the other parts [...]]]></description>
			<content:encoded><![CDATA[<div class="interview">
<div class="intro">
<p><img src="http://yuiblog.com/assets/stoyan.jpg" alt="Stoyan Stefanov." align="right" hspace="10" vspace="5"><em><strong>About the Author:</strong><a href="http://www.phpied.com"> Stoyan Stefanov</a> is a Yahoo! web developer working for the <a href="http://developer.yahoo.com/performance/">Exceptional Performance</a> team and leading the development of the <a href="http://developer.yahoo.com/yslow/">YSlow</a> performance tool. He also an open-source contributor, conference speaker and technical writer: his latest book is called <a href="http://www.packtpub.com/object-oriented-javascript-applications-libraries/book">Object-Oriented JavaScript</a>.</em></p>
</div>
</div>
<p><em>This is part 1 in an ongoing series. You can read the other parts here:</em></p>
<ul>
<li><a href="http://yuiblog.com/blog/2008/11/04/imageopt-2/">Image Optimization Part 2: Selecting the Right File Format</a></li>
<li><a href="http://yuiblog.com/blog/2008/11/14/imageopt-3/">Image Optimization Part 3: Four Steps to File Size Reduction</a></li>
<li><a href="http://yuiblog.com/blog/2008/12/05/imageopt-4/">Image Optimization Part 4: Progressive JPEG…Hot or Not?</a></li>
</ul>
<p>This is the first in a series of posts about image optimization. In this series, I&#8217;ll explore how images affect web site performance and what can you do to your images in order to improve page loading times. (I won&#8217;t say how many posts in this series, so that I can claim later that I underpromised and overdelivered&#8230;).</p>
<p>When you think about improving page response time, one of the first obvious things to think about is the page weight. It&#8217;s obvious that, all things being equal, the heavier a page is the slower it will be. If we take this to the extreme, we can say that the fastest page you can possibly have is the blank page. Once you start adding stuff to the blank page, you&#8217;re only making it slower. </p>
<p>On a more serious note, it really is up to you how much content you want to put on a page, so let&#8217;s focus on what comes next. After you&#8217;ve settled on the content, it&#8217;s your job to make sure the content and components are as small as possible. Following our <a href="http://developer.yahoo.com/performance/rules.html">Yahoo! performance best practices</a>, you should make sure that all plain text components (HTML, XML, CSS, JavaScript&#8230;) are sent compressed over the wire and that you minify CSS and JavaScript. </p>
<p>But what about the images, how can you speed them up without sacrificing quality and looks? But first, does it really matter?</p>
<h3>How important are the images?</h3>
<p>Before we start, let&#8217;s see if we should even bother with images. Lately we&#8217;ve been witnessing the rise of rich internet applications with lots of JavaScript &mdash; by &#8220;lots&#8221; meaning sometimes 300K or more worth of JavaScript code. In other cases, especially in advertising, Flash seems to be the weapon of choice. So, on average, how much of the page weight is images. It&#8217;s easy to answer this question by just looking at <a href="http://www.alexa.com/site/ds/top_sites">Alexa&#8217;s top 10 websites</a> in the world (as of October 2008) and use <a href="http://developer.yahoo.com/yslow/">YSlow</a> to check what percent of the total page weight is images. The results are given below.</p>
<table border="1" id="imagekweight" width="350">
<caption>Percentage of page weight that goes to images, average 46.6%</caption>
<tbody>
<tr>
<td>1</td>
<td>Yahoo!</td>
<td>39%</td>
</tr>
<tr>
<td>2</td>
<td>Google</td>
<td>75%</td>
</tr>
<tr>
<td>3</td>
<td>YouTube</td>
<td>37%</td>
</tr>
<tr>
<td>4</td>
<td>Live.com</td>
<td>94%</td>
</tr>
<tr>
<td>5</td>
<td>Facebook</td>
<td>39%</td>
</tr>
<tr>
<td>6</td>
<td>MSN</td>
<td>59%</td>
</tr>
<tr>
<td>7</td>
<td>MySpace</td>
<td>36%</td>
</tr>
<tr>
<td>8</td>
<td>Wikipedia</td>
<td>34%</td>
</tr>
<tr>
<td>9</td>
<td>Blogger</td>
<td>28%</td>
</tr>
<tr>
<td>10</td>
<td>Yahoo! JP</td>
<td>25%</td>
</tr>
</tbody>
</table>
<style type="text/css">
	#chart
	{
		width: 530px;
		height: 350px;
	}</p>
<p>	.chart_title
	{
		display: block;
		font-size: 1.2em;
		font-weight: bold;
		margin-bottom: 0.4em;
	}
</style>
<div id="chart">
</div>
<p><!--Include YUI Loader: --><br />
<script type="text/javascript" src="http://yui.yahooapis.com/2.6.0/build/yuiloader/yuiloader-min.js"></script> </p>
<p><!--Use YUI Loader to bring in your other dependencies: --><br />
<script type="text/javascript"> 
// Instantiate and configure YUI Loader: 
(function() { </p>
<p>	var initChart = function() {</p>
<p>		YAHOO.widget.Chart.SWFURL = "http://yui.yahooapis.com/2.6.0/build//charts/assets/charts.swf";</p>
<p>		YAHOO.example.imageweight =
		[
			{ company: "Yahoo!", percent: 39},
			{ company: "Google", percent: 75},
			{ company: "YouTube", percent: 37},
			{ company: "Live", percent: 94},
			{ company: "Facebook", percent: 39},
			{ company: "MSN", percent: 59},
			{ company: "MySpace", percent: 36},
			{ company: "Wikip.", percent: 34},
			{ company: "Blogger", percent: 28},
			{ company: "Y! Japan", percent: 25}
		];</p>
<p>		var myDataSource = new YAHOO.util.DataSource( YAHOO.example.imageweight );
		myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSARRAY;
		myDataSource.responseSchema =
		{
			fields: [ "company", "percent" ]
		};</p>
<p>		var seriesDef = 
		[
			{ displayName: "% Pageweight in Images", yField: "percent" },
		];</p>
<p>		var percentAxis = new YAHOO.widget.NumericAxis();
		percentAxis.minimum = 0;
		percentAxis.maximum = 100;</p>
<p>		var mychart = new YAHOO.widget.ColumnChart( "chart", myDataSource,
		{
			yAxis: percentAxis,
			series: seriesDef,
			xField: "company",
			yField: "percent",
			style:
			{
				padding: 20,
				font: {
					size:9,
					color:"666666"
					},
				legend:
				{
					display: "bottom",
					padding: 7,
					spacing: 5,
					font:
					{
						color:"#666666",
						size: 12
					}
				}
			}
		});</p>
<p>	}</p>
<p>    var loader = new YAHOO.util.YUILoader({  
        require: ["charts"], 
        loadOptional: false, 
        combine: true, 
        filter: "MIN", 
        allowRollup: true, 
        onSuccess: initChart 
    }); </p>
<p>// Load the files using the insert() method. 
loader.insert(); 
})(); 
</script> </p>
<p>On average, <strong>46.6%</strong> of the page weight for these popular sites consists of images, included either inline with <code>&lt;img&gt;</code> tags or via CSS stylesheets. Other studies show that this percent can be even higher, depending on the cross section of sites you examine. The exact number is not important, because every site is unique and different from the average; for example <a href="http://amazon.com/">Amazon&#8217;s</a> home page was made of 75% images at the time of the experiment.</p>
<p>This is a massive percentage and it tells us one thing: There&#8217;s huge potential to improve the performance of websites if we can improve the way we handle the image payload. By focusing on images you can make a difference and delight your site visitors with a faster and more pleasant experience.</p>
<h3>To be continued&#8230;</h3>
<p>Over the course of the following weeks, we&#8217;ll be publishing more about image optimization. The topics for discussion include:</p>
<ul>
<li>different image formats and how to pick the right one</li>
<li>ways to put your images on a diet without compromising quality</li>
<li>optimizing generated images</li>
<li>the effect of using <code>AlphaImageLoader</code></li>
<li>favicons</li>
<li>CSS sprites</li>
<li>serving images faster</li>
</ul>
<p>The series of posts will not require Photoshop or other designers&#8217; domain-specific knowledge, so it should be pretty easy for anyone to learn and apply these techniques. More to come soon&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yuiblog.com/blog/2008/10/29/imageopt-1/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Non-blocking JavaScript Downloads</title>
		<link>http://www.yuiblog.com/blog/2008/07/22/non-blocking-scripts/</link>
		<comments>http://www.yuiblog.com/blog/2008/07/22/non-blocking-scripts/#comments</comments>
		<pubDate>Tue, 22 Jul 2008 18:41:39 +0000</pubDate>
		<dc:creator>Stoyan Stefanov</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://yuiblog.com/blog/2008/07/22/non-blocking-scripts/</guid>
		<description><![CDATA[

About the Author: Stoyan Stefanov is a Yahoo! web developer working for the Exceptional Performance team and leading the development of the YSlow performance tool. He also an open-source contributor, conference speaker and technical writer: his latest book is called Object-Oriented JavaScript.


External JavaScript files block downloads and hurt your page performance, but there is an [...]]]></description>
			<content:encoded><![CDATA[<div class="interview">
<div class="intro">
<p><img src="http://yuiblog.com/assets/stoyan.jpg" alt="Stoyan Stefanov." align="right" hspace="10" vspace="5"><em><strong>About the Author:</strong><a href="http://www.phpied.com"> Stoyan Stefanov</a> is a Yahoo! web developer working for the <a href="http://developer.yahoo.com/performance/">Exceptional Performance</a> team and leading the development of the <a href="http://developer.yahoo.com/yslow/">YSlow</a> performance tool. He also an open-source contributor, conference speaker and technical writer: his latest book is called <a href="http://www.packtpub.com/object-oriented-javascript-applications-libraries/book">Object-Oriented JavaScript</a>.</em></p>
</div>
</div>
<p>External JavaScript files block downloads and hurt your page performance, but there is an easy way to work around this problem: use dynamic scripts tags and load scripts in parallel, improving the page loading speed and the user experience.</p>
<h2>The problem: scripts block downloads</h2>
<p>Let&#8217;s first take a look at what the problem is with the script downloads. The thing is that before fully downloading and parsing a script, the browser can&#8217;t tell what&#8217;s in it. It may contain <code>document.write()</code> calls which modify the DOM tree or it may even contain <code>location.href</code> and send the user to a whole new page. If that happens, any components downloaded from the previous page may never be needed. In order to avoid potentially useless downloads, browsers first download, parse and execute each script before moving on with the queue of other components waiting to be downloaded. As a result, any script on your page blocks the download process and that has a negative impact on your page loading speed.</p>
<p>Here&#8217;s how the timeline looks like when downloading a slow JavaScript file (exaggerated to take 1 second). The script download (the third row in the image) blocks the two-by-two parallel downloads of the images that follow after the script:</p>
<p><img src="http://yuiblog.com/assets/non-block-yui/1.png" alt="Timeline - Blocking behavior of JavaScript files" width="325" height="223" /></p>
<p><a href="http://yuiblog.com/assets/non-block-yui/before.html">Here&#8217;s the example</a> to test yourself.</p>
<h2>Problem 2: number of downloads per hostname</h2>
<p>Another thing to note in the timeline above is how the images following the script are downloaded two-by-two. This is because of the restriction of how many components can be downloaded in parallel. In IE &lt;= 7 and Firefox 2, it&#8217;s two components at a time (following the HTTP 1.1 specs), but both IE8 and FF3 increase the default to 6.</p>
<p>You can work around this limitation by using multiple domains to host your components, because the restriction is two components <em>per hostname</em>. For more information of this topic check the article &#8220;<a href="http://yuiblog.com/blog/2007/04/11/performance-research-part-4/">Maximizing Parallel Downloads in the Carpool Lane</a>&#8221; by Tenni Theurer.</p>
<p>The important thing to note is that <em>JavaScripts block downloads across all hostnames</em>. In fact, in the example timeline above, the script is hosted on a different domain than the images, but it still blocks them.</p>
<h2>Scripts at the bottom to improve user experience</h2>
<p>As <a href="http://developer.yahoo.com/performance/rules.html">Yahoo!&#8217;s Performance rules</a> advise, you should put the scripts at the bottom of the page, towards the closing <code>&lt;/body&gt;</code> tag. This doesn&#8217;t really make the page load faster (the script still has to load), but helps with the progressive rendering of the page. The user perception is that the page is faster when they can see a visual feedback that there is progress.</p>
<h2>Non-blocking scripts</h2>
<p>It turns out that there is an easy solution to the download blocking problem: include scripts dynamically via DOM methods. How do you do that? Simply create a new <code>&lt;script&gt;</code> element and append it to the <code>&lt;head&gt;</code>:</p>
<pre>
var js = document.createElement('script');
js.src = 'myscript.js';
var head = document.getElementsByTagName('head')[0];
head.appendChild(js);
</pre>
<p>Here&#8217;s the same test from above, modified to use the script node technique. Note that the third row in the image takes just as long to download, but the other resources on the page are loading simultaneously:</p>
<p><img src="http://yuiblog.com/assets/non-block-yui/2.png" alt="Non-blocking JavaScript timeline" width="325" height="206" /></p>
<p><a href="http://yuiblog.com/assets/non-block-yui/after.html">Test example</a></p>
<p>As you can see the script file no longer blocks the downloads and the browser starts fetching the other components in parallel. And the overall response time is cut in half.</p>
<h2>Dependencies</h2>
<p>A problem with including scripts dynamically would be satisfying the dependencies. Imagine you&#8217;re downloading 3 scripts and <code>three.js</code> requires a function from <code>one.js</code>. How do you make sure this works?</p>
<p>Well, the simplest thing is to have only one file, this way not only avoiding the problem, but also improving performance by minimizing the number of  HTTP requests (<a href="http://developer.yahoo.com/performance/rules.html#num_http">performance rule #1</a>).</p>
<p>If you do need several files though, you can attach a listener to the script&#8217;s <code>onload</code> event (this will work in Firefox) and the <code>onreadystatechange</code> event (this will work in IE). Here&#8217;s a <a href="http://www.phpied.com/javascript-include-ready-onload/">blog post</a> that shows you how to do this. To be fully cross-browser compliant, you can do something else instead: just include a variable at the bottom of every script, as to signal &#8220;I&#8217;m ready&#8221;. This variable may very well be an array with elements for every script already included.</p>
<h2>Using YUI Get utility</h2>
<p>The <a href="http://developer.yahoo.com/yui/get/">YUI Get Utility</a> makes it easy for you to use script includes. For example if you want to load 3 files, <code>one.js</code>, <code>two.js</code> and <code>three.js</code>, you can simply do:</p>
<pre>
var urls = ['one.js', 'two.js', 'three.js'];
YAHOO.util.Get.script(urls);
</pre>
<p>YUI Get also helps you with satisfying dependencies, by loading the scripts in order and also by letting you pass an <code>onSuccess</code> callback function which is executed when the last script is done loading. Similarly, you can pass an <code>onFailure</code> function to handle cases where scripts fail to load.</p>
<pre>
var myHandler = {
    onSuccess: function(){
        alert(':))');
    },
    onFailure: function(){
        alert(':((');
    }
};

var urls = ['1.js', '2.js', '3.js'];
YAHOO.util.Get.script(urls, myHandler);
</pre>
<p>Again, note that YUI Get will request the scripts in sequence, one after the other. This way you don&#8217;t download all the scripts in parallel, but still, the good part is that the scripts are not blocking the rest of the images and the other components on the page. <a href="http://developer.yahoo.com/yui/examples/get/get-script-basic.html">Here&#8217;s a good example and tutorial on using YUI Get to load scripts</a>.</p>
<p>YUI Get can also include stylesheets dynamically through the method<br />
<code>YAHOO.util.Get.css()</code> [<a href="http://developer.yahoo.com/yui/examples/get/get-css-basic.html">example</a>].</p>
<p>Which brings us to the next question:</p>
<h2>And what about stylesheets?</h2>
<p>Stylesheets don&#8217;t block downloads in IE, but they do in Firefox. Applying the same technique of dynamic inserts solves the problem. You can create dynamic link tags like this:</p>
<pre>
var h = document.getElementsByTagName('head')[0];
var link = document.createElement('link');
link.href = 'mycss.css';
link.type = 'text/css';
link.rel = 'stylesheet';
h.appendChild(link);
</pre>
<p>This will improve the loading time in Firefox significantly, while not affecting the loading time in IE.</p>
<p>Another positive side effect of the dynamic stylesheets (in FF) is that it helps with the progressive rendering. Usually both browsers will wait and show blank screen until the very last piece of stylesheet information is downloaded, and only then they&#8217;ll start rendering. This behavior saves them the potential work of re-rendering when new stylesheet rules come down the wire. With dynamic <code>&lt;link&gt;</code>s this is not happening in Firefox, it will render without waiting for all the styles and then re-render once they arrive. IE will behave as usual and wait.</p>
<p>But before you go ahead and implement dynamic <code>&lt;link&gt;</code> tags, consider the violation of the rule of separation of concerns: your page <em>formatting</em> (CSS) will be dependent on <em>behavior</em> (JS). In addition, this problem is going to be addressed in future Firefox versions.</p>
<h2>Other ways?</h2>
<p>There are other ways to achieve the non-blocking scripts behavior, but they all have their drawbacks.</p>
<table border="1">
<tr>
<th>Method</th>
<th>Drawback</th>
</tr>
<tr>
<td>Using <code>defer</code> attribute of the <code>script</code> tag</td>
<td>IE-only, unreliable even there</td>
</tr>
<tr>
<td>Using <code>document.write()</code> to write a script tag</td>
<td>
<ol>
<li>Non-blocking behavior is in IE-only </li>
<li><code>document.write</code> is not a recommended coding practice</li>
</ol>
</td>
</tr>
<tr>
<td><code>XMLHttpRequest</code> to get the source then execute with <code>eval()</code>.</td>
<td>
<ol>
<li>&#8220;<code>eval()</code> is evil&#8221;</li>
<li>same-domain policy restriction</li>
</ol>
</td>
</tr>
<tr>
<td>XHR request to get the source, create a new script tag and set its content</td>
<td>
<ol>
<li>more complex</li>
<li>same-domain policy</li>
</ol>
</td>
</tr>
<tr>
<td>Load script in an iframe</td>
<td>
<ol>
<li>complex</li>
<li>iframe overhead</li>
<li>same-domain policy</li>
</ol>
</td>
</tr>
</table>
<h2>Future</h2>
<p>Safari and IE8 are already changing the way scripts are getting loaded. Their idea is to download the scripts in parallel, but execute them in the sequence they&#8217;re found on the page. It&#8217;s likely that one day this blocking problem will become negligible, because only a few users will be using IE7 or lower and FF3 or lower. Until then, a dynamic script tag is an easy way around the problem.</li>
<h2>Summary</h2>
<ul>
<li>Scripts block downloads in FF and IE browsers and this makes your pages load slower.</li>
<li>An easy solution is to use dynamic <code>&lt;script&gt;</code> tags and prevent blocking.</li>
<li><a href="http://developer.yahoo.com/yui/get/">YUI Get Utility</a> makes it easier to do script and style includes and manage dependencies.</li>
<li>You can use dynamic <code>&lt;link&gt;</code> tags too, but consider the separation of concerns first.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.yuiblog.com/blog/2008/07/22/non-blocking-scripts/feed/</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
		<item>
		<title>Performance Research, Part 6: Less is More — Serving Files Faster by Combining Them</title>
		<link>http://www.yuiblog.com/blog/2008/07/21/performance-research-part-6/</link>
		<comments>http://www.yuiblog.com/blog/2008/07/21/performance-research-part-6/#comments</comments>
		<pubDate>Mon, 21 Jul 2008 16:03:15 +0000</pubDate>
		<dc:creator>Tenni Theurer</dc:creator>
				<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://yuiblog.com/blog/2008/07/21/performance-research-part-6/</guid>
		<description><![CDATA[

This article is the sixth in a series of YUIBlog articles describing experiments conducted to learn more about optimizing web page performance (Part 1, Part 2, Part 3, Part 4, Part 5).


In Performance Research Part 1, we discussed how reducing the number of HTTP requests has the biggest impact on improving the response time and [...]]]></description>
			<content:encoded><![CDATA[<div class="interview">
<div class="intro">
<p><em>This article is the sixth in a series of YUIBlog articles describing experiments conducted to learn more about optimizing web page performance (<a href="http://yuiblog.com/blog/2006/11/28/performance-research-part-1/">Part 1</a>, <a href="http://yuiblog.com/blog/2007/01/04/performance-research-part-2/">Part 2</a>, <a href="http://yuiblog.com/blog/2007/03/01/performance-research-part-3/">Part 3</a>, <a href="http://yuiblog.com/blog/2007/04/11/performance-research-part-4/">Part 4</a>, <a href="http://yuiblog.com/blog/2008/02/06/iphone-cacheability/">Part 5</a>).</em></p>
</p></div>
</div>
<p>In <a href="http://yuiblog.com/blog/2006/11/28/performance-research-part-1/">Performance Research Part 1</a>, we discussed how reducing the number of HTTP requests has the biggest impact on improving the response time and is often the easiest performance improvement to make. One technique without having to simplify the page design is to combine multiple scripts into a single script, and similarly combine multiple stylesheets into a single stylesheet.</p>
<blockquote><p>Combining multiple files reduces the extra bytes from HTTP headers as well as potential transfer latency caused by TCP slow starts, packet losses, etc.</p></blockquote>
<p>Figure 1 shows a graphical view of how time is spent loading a page with six separate scripts. Notice that for every file, the browser makes a separate HTTP request to retrieve the file. The gaps between the scripts indicate the time the browser takes to parse and render each script. Figure 2 shows the how time is spent loading a page with the same six scripts combined into a single script.</p>
<div class="figure">
<h4><strong>Figure 1.</strong> Loading a page with six separate scripts</h4>
<p><img src="http://yuiblog.com/assets/six-separate-scripts.gif" alt="Figure 1. Loading a page with six separate scripts" width="487" height="114" id="six-separate-scripts"/></p>
</div>
<div class="figure">
<h4><strong>Figure 2.</strong> Loading a page with one combined script</h4>
<p><img src="http://yuiblog.com/assets/one-single-script.gif" alt="Figure 1. Loading a page with one combined script" width="484" height="63" longdesc="six-separate-scripts.gif" id="six-separate-scripts"/></p>
</div>
<p>Combining JavaScript and CSS files as part of the development process can be burdensome. It usually makes sense during development to organize the code into logical modules as separate files. Typically, combining those separate files before product release is either a manual process or part of a build process. Every time one of the individual files is changed, the larger file needs to be re-combined and re-pushed. The cost of this across an organization as large as Yahoo! is significant.</p>
<h3>Serve Files Faster using Combo Handler</h3>
<p>Combo Handler, built in collaboration by <a href="http://developer.yahoo.com/performance/">Yahoo!&#8217;s Exceptional Performance team</a> and the groups that support our CDN, is one solution to combine multiple files into a single, larger file.</p>
<p>Combo Handler provides a way to allow developers to maintain the logical organization of their code in separate files, while achieving the advantages of combining those into a single file as part of the final user experience. It alleviates the need for the time-consuming re-build and re-push processes. In addition, Combo Handler integrates seamlessly into a content delivery network, taking full advantage of the <a href="http://developer.yahoo.com/performance/rules.html#cdn">benefits of a CDN</a> while reducing the drawbacks of dynamically combining separate files.</p>
<p>We&#8217;ve been using this service across many Yahoo! properties for some time now to help improve end users&#8217; response times. Thanks to the YUI team, it is <a href="http://yuiblog.com/blog/2008/07/16/combohandler/">now available</a> to all of you that are using the Yahoo!-hosted YUI JavaScript files. (Note: Combo-handling of CSS files is not supported at this time.) <a href="http://developer.yahoo.com/yui/articles/hosting/#configure">Head over to the YUI Configurator</a> to generate combo-ready filepaths customized for your specific YUI implementation.</p>
<h3>Combo Handler Best Practices</h3>
<p>When using Combo Handler to combine files, pay special attention to the order in which the files are specified. Not only could there be file dependencies, browsers will only use the cached version of a file if the filename extracted from the URL is identical. For example, suppose the following smaller files (<code>dom.js</code> and <code>event.js</code>) are combined into a single larger file using Combo Handler:</p>
<pre>

http://yui.yahooapis.com/combo?event.js&#038;dom.js

http://yui.yahooapis.com/combo?dom.js&#038;event.js
</pre>
<p>In the example above, the browser will download and cache both files separately because the filenames are actually different.</p>
<p>Also, you may not always want to combine all files into one single file. Suppose you have one or more scripts that are shared across multiple pages in your site in addition to scripts that are only used on specific pages. By combining everything into one large file and using this file across your entire site, some pages will spend time downloading more than it really needs. Instead, take a look at different types of combinations. You might combine the scripts that are used in every page across your site into one script. Then for each page or group of pages, combine common scripts into another separate script.</p>
<h3>Yahoo! HotJobs Combines and Reduces Response Time by 8%!</h3>
<p>The <a href="http://developer.yahoo.com/performance/">Exceptional Performance</a> team ran an experiment with <a href="http://hotjobs.yahoo.com">Yahoo! HotJobs</a> to determine the response time savings our users would benefit from by combining multiple files into a single file. Two real user test buckets were created for this experiment. In one bucket, users visited a page with six JavaScript files left uncombined. In the second bucket, users visited the same page with the six JavaScript files combined into one single file. </p>
<blockquote><p>Combining six JavaScript files into one single JavaScript file improved performance by almost 8% on average for Yahoo! HotJobs&#8217; users on broadband bandwidth speeds and 5% for users on lan. No design or feature changes required!</p></blockquote>
<p>Keep in mind that the page we tested was already highly optimized for performance and had a <a href="http://developer.yahoo.com/yslow">YSlow</a> &#8220;A&#8221; grade. The response time savings depend on a number of factors including number of files combined, browser caching patterns, etc. This experiment supported our previous research, which indicated that reducing HTTP requests is an effective way to improve response times for our end users.</p>
<h3>Takeaways</h3>
<p>Improve response times by combining multiple JavaScript and CSS files. Yahoo!&#8217;s <a href="http://yuiblog.com/blog/2008/07/16/combohandler/">Combo Handler</a> Service is one solution that provides a way to make fewer HTTP requests for Yahoo!-hosted JavaScript files, and also leverages the benefits of a Content Delivery Network.</p>
<ul>
<li>Combine scripts and stylesheets to reduce HTTP requests.</li>
<li>Look at different types of file combinations.</li>
<li>Avoid users from having to download more than they really need.</li>
<li>Pay special attention to the order in which files are combined.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.yuiblog.com/blog/2008/07/21/performance-research-part-6/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
	</channel>
</rss>
