<?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>YUI Blog » Performance</title>
	
	<link>http://www.yuiblog.com/blog</link>
	<description>The official blog of the YUI Project.</description>
	<lastBuildDate>Fri, 17 May 2013 21:46:52 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<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>Shifter, fast YUI module building</title>
		<link>http://www.yuiblog.com/blog/2012/08/27/shifter-fast-yui-module-building/</link>
		<comments>http://www.yuiblog.com/blog/2012/08/27/shifter-fast-yui-module-building/#comments</comments>
		<pubDate>Mon, 27 Aug 2012 15:21:48 +0000</pubDate>
		<dc:creator>Dav Glass</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://www.yuiblog.com/blog/2012/08/24/</guid>
		<description><![CDATA[Our build system has been on my mind lately, our old ant system was just getting too slow to keep up with the changes I was making and it was making it very difficult for our Automatic Travis Pull Request builds to test incoming changes properly if it took so long to build our modules. [...]]]></description>
				<content:encoded><![CDATA[<p>Our build system has been on my mind lately, our old ant system was just getting too slow to keep up with the changes I was making and it was making it very difficult for our Automatic <a href="http://travis-ci.org/yui/yui3" title="Travis">Travis</a> Pull Request builds to test incoming changes properly if it took so long to build our modules.</p>
<p>One night a week or so back I couldn&#8217;t sleep, so I built <a href="http://yui.github.com/shifter/" title="Shifter">Shifter</a>. Shifter is a command line tool built in <a href="http://nodejs.org" title="Node.js">Node.js</a> using the <a href="http://gearjs.org/" title="Gear.js">Gear.js</a> build system. Gear.js was chosen as the base system because it&#8217;s what powers <a href="https://github.com/yahoo/mojito-shaker">Mojito Shaker</a> plus it&#8217;s small and good at what it does.</p>
<p><img src="http://www.yuiblog.com/blog/wp-content/uploads/2012/08/ShifterBlog.jpg" alt="" title="ShifterBlog" width="600" height="217" class="aligncenter size-full wp-image-5475" /></p>
<h3>Why It&#8217;s Faster</h3>
<p>Shifter get&#8217;s a lot of its speed from streaming changes throughout the build process. Our old builder would write files into a temp directory, then perform its tasks on them (compress, filter, concat, etc). This made it inherently slow to begin with. Shifter processes all its files as strings and only writes to disk when it has completed its job. Shifter replaces our need to use Ant, but we still have a Java dependency (for YUI Compressor and YUI Test Coverage). However, these Java dependencies have been streamlined so they don&#8217;t use file access either. Both <a href="https://npmjs.org/package/yuicompressor">YUI Compressor</a> and <a href="https://npmjs.org/package/yuitest-coverage">YUI Test Coverage</a> have npm packages that allow them to be required as a Node.js module and used asynchronously. YUI Test Coverage was updated to allow you to pipe a file into the jar and print the results to standard out similar to the way YUI Compressor handles it. This allows the Node.js module to spawn the Java process under the hood while piping the files into the jar and not writing files to disk.</p>
<p>The other way that Shifter optimizes builds is that it doesn&#8217;t do anything twice if it doesn&#8217;t have to. With the old builder, modules would get built once for debug, raw and minified files, then again for rollups and again for coverage files. This wasted a lot of cycles, but it was more of a limitation of ant (XML is not a coding language). Shifter deals with rollups a little differently. Instead of building the files again, the default action for a rollup is merging several prebuilt modules into one file and stamping it with the rollup module stamp (the <code>YUI.add</code> wrapper.</p>
<p>Depending on your system, you should see build times improved anywhere from 30% to 1000%!</p>
<h3>Installation</h3>
<p>Installation is simple, <code>npm -g install shifter</code>, it&#8217;s been tested on OSX, Linux and Windows as long as you are running a recent Node.js build.</p>
<h3>When To Use It</h3>
<p>We are recommending anyone that builds a YUI module (for themselves or as a contribution) should switch to using Shifter. When you run Shifter on your module the first time, it will parse your ant build files for you and create a <code>build.json</code> file to use in their place. Once you have verified that your module builds properly, we are recommending that you remove your ant files and forget about them. </p>
<h3>Gallery Builds</h3>
<p>For now, please do <strong>not</strong> remove your ant files from your Gallery modules. The current Gallery build is being rewritten, once that is complete it will have support for Shifter builds (actually it will only use Shifter). For now, feel free to use it to build your Gallery modules but remember that if you submit a CDN request you must have your ant files in your repository.</p>
<h3>Docs and Stuff</h3>
<p>Of course it <a href="http://yui.github.com/shifter/">has docs</a>, how else are you going to know how to if it&#8217;s a feature or a bug! I&#8217;ve also documented the relevant keys from the <a href="http://yui.github.com/shifter/#build.json">build.json</a> file to help when you are building your own.</p>
<p>And as always, <a href="https://github.com/yui/shifter">Pull Requests</a> are always welome!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yuiblog.com/blog/2012/08/27/shifter-fast-yui-module-building/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Next-Gen YSlow powered by YUI</title>
		<link>http://www.yuiblog.com/blog/2011/07/18/next-gen-yslow-powered-by-yui/</link>
		<comments>http://www.yuiblog.com/blog/2011/07/18/next-gen-yslow-powered-by-yui/#comments</comments>
		<pubDate>Tue, 19 Jul 2011 04:17:20 +0000</pubDate>
		<dc:creator>Marcel Duran</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://www.yuiblog.com/blog/2011/07/15/</guid>
		<description><![CDATA[A couple of weeks ago, Yahoo! announced YSlow for Mobile at Velocity 2011, bringing the power of YSlow performance analysis to the mobile world. YSlow for Mobile works as a bookmarklet, making it possible to run on browsers other than Firefox (as an add-on) or Chrome (as an extension). The YSlow architecture was partially redesigned [...]]]></description>
				<content:encoded><![CDATA[<p>A couple of weeks ago, Yahoo! announced <a href="http://developer.yahoo.com/blogs/ydn/posts/2011/06/yslowmobile/">YSlow for Mobile</a> at <a href="http://velocityconf.com/velocity2011/public/schedule/detail/20287">Velocity 2011</a>, bringing the power of YSlow performance analysis to the mobile world.</p>
<p><a href="http://developer.yahoo.com/yslow/mobile/">YSlow for Mobile</a> works as a <a href="http://en.wikipedia.org/wiki/Bookmarklet">bookmarklet</a>, making it possible to run on browsers other than <a href="https://addons.mozilla.org/en-US/firefox/addon/5369">Firefox (as an add-on)</a> or <a href="https://chrome.google.com/webstore/detail/ninejjcohidippngpapiilnmkgllmakh">Chrome (as an extension)</a>.</p>
<p>The YSlow architecture was partially redesigned to work cross-platform and YUI was the essential factor in make sandboxing, cross-browser abstraction and simple YQL access possible.</p>
<h3>Sandboxing</h3>
<p>In order to be embedded on a page without interfering with performance analysis and without messing with the page itself, YSlow is a bookmarklet that injects JavaScript and CSS into any page by leveraging the power of YUI sandboxing:</p>
<p>Bookmarklet URL:</p>
<pre>
javascript:(function (y, p, o) {
    p = y.body.appendChild(y.createElement('iframe'));
    p.id = 'YSLOW-bookmarklet';
    p.style.cssText = 'display:none';
    o = p.contentWindow.document;
    o.open().write('
        &lt;head&gt;
        &lt;body onload = "
            YUI_config = {
                win: window.parent,
                doc: window.parent.document
            };
            var d = document;
            d.getElementsByTagName(\'head\')[0]
                .appendChild(
                    d.createElement(\'script\')
                ).src = \'http://d.yimg.com/jc/yslow-bookmarklet.js\'"
        &gt;
    ');
    o.close()
}(document))
</pre>
<p>The code above:</p>
<ul>
<li>creates an empty iframe;</li>
<li>appends it to the page body;</li>
<li>hides the iframe*;</li>
<li>gets its window handler;</li>
<li>writes into its content the body of the iframe;</li>
<li>this body is empty but has an <code>onload</code> event</li>
<li>the <code>onload</code> event defines how to inject YSlow JS:
<ul>
<li>sets <code>YUI_config</code>, so <code>win</code> and <code>doc</code> points to the page being analyzed <code>window</code> and <code>document</code> respectively</li>
<li>dynamically injects YSlow URL by creating a <code>script</code> element into iframe&#8217;s <code>head</code></li>
</ul>
</li>
</ul>
<p><i>* the iframe is displayed by the time all YSlow presentation assets are loaded</i></p>
<p>This will place an iframe into the page being analyzed. This iframe will act as a sandboxed environment and YSlow will reside within it. Since the iframe is dynamically created without the <code>src</code> attribute, it will have access to its parent (the page being analyzed) because there&#8217;s no <a href="https://developer.mozilla.org/en/Same_origin_policy_for_JavaScript">same origin policy</a> violation happening there.</p>
<p>The <a href="http://developer.yahoo.com/yui/3/api/config.html">YUI_config</a> object is handy because it sets <code>win</code> and <code>doc</code> to the iframe&#8217;s parent (the page being analyzed), thus any new YUI instance will be bound to the parent document by default, wiring any call to <code>Y.all</code> and <code>Y.one</code> through <code>Y.config.win</code> or <code>Y.config.doc</code> from the YUI <a href="http://developer.yahoo.com/yui/3/yui/#use"><code>use</code></a> callback.</p>
<p>YSlow&#8217;s presentation is handled by the iframe <code>window</code> and <code>document</code> references, allowing the YSlow main script to render the markup as well as fetch the external CSS within this iframe without conflicting with the parent page&#8217;s styles. YSlow scans the parent page in order to get all the components (images, scripts, links, background-images, flash, etc.) required for later performance analysis. This is done by accessing <code>Y.config.win</code> and <code>Y.config.doc</code>, since they refer to the parent page.</p>
<h3>Cross-browser abstraction</h3>
<p>Being a bookmarklet, YSlow for Mobile is supposed to work on any browser*. YUI abstracts cross-browser issues by normalizing browser differences, resulting in a clean, easy-to-read and maintainable codebase.</p>
<p>YSlow was not fully ported to YUI 3 &mdash; only the controller layer (from the upcoming App component) for now &mdash; but still, all DOM manipulation and event handling are done by the <a href="http://developer.yahoo.com/yui/3/node/"><code>node</code></a> and <a href="http://developer.yahoo.com/yui/3/event/"><code>event</code></a> modules. In future releases we plan to port more YSlow features to YUI 3.</p>
<p><i>* not all browsers are currently supported</i></p>
<h3>YQL</h3>
<p>YSlow analyzes pages by checking the HTTP headers for the components found on the page. HTTP response headers are not available in the page, hence those components need to be requested again in order for YSlow get the response header information. This could be achieved by requesting the list of component URLs through XmlHttpRequest (AJAX) but unfortunately due to <a href="http://en.wikipedia.org/wiki/Same_origin_policy">same origin policy restriction</a>, this is not possible unless all components are in the same domain as the page which is very unlikely.</p>
<p>A common workaround for same origin policy restriction is using JSONP, where an external server works as a proxy requesting the list of components URLs and retrieving their HTTP response headers on behalf of YSlow. Due to YSlow&#8217;s popularity and recent mobile performance analysis efforts, we&#8217;re expecting quite heavy traffic for the YSlow for Mobile bookmarklet. In order to support such traffic, <a href="http://developer.yahoo.com/yql/">YQL</a> was the scalable solution adopted by YSlow through an <a href="http://www.datatables.org/">open data table</a> named <a href="http://developer.yahoo.com/yql/console/?q=select%20*%20from%20data.headers%20where%20url%3D%22http%3A//getyslow.com/%22&#038;env=http%3A%2F%2Fdatatables.org%2Falltables.env">data.headers</a>, which retrieves the response headers and content for a given list of URLs while impersonating the user-agent to ensure the expected content is retrieved.</p>
<p>The <a href="http://developer.yahoo.com/yui/3/yql/">YQL Query</a> component does all the work of managing YQL queries while managing JSONP requests under the hood, making the YSlow controller code much simpler and easy-to-maintain.</p>
<h3>Future enhancements: New YSlow for Mobile friendly interface</h3>
<p>Currently the YSlow for Mobile user experience is the same as the desktop experience. Dealing with a long list of performance analysis data is not the best experience on small smart-phone screens. Since YUI also abstracts <a href="http://developer.yahoo.com/yui/3/event/#gestures">cross-device gestures</a>, YSlow for Mobile will get a brand new mobile-friendly interface in future releases.</p>
<h3>Performance of performance tool</h3>
<p>YSlow for Mobile deployment was made carefully considering its performance impact on the load time of the page being analyzed. The YUI 3 modules used on YSlow were scrutinized to include only the modules needed to load YSlow as fast as possible. The YUI seed file and Loader <a href="http://developer.yahoo.com/yui/3/configurator/">were not included</a> since all necessary modules and submodules were combined together following <a href="http://developer.yahoo.com/yui/theater/video.php?v=grove-zen">Ryan Grove&#8217;s Performance Zen</a> tips, which made it possible to load everything together into a single small single request: yslow-bookmarklet.js: 204KB, 66KB (gzip) where:</p>
<ul>
<li>YUI: 75KB, 27KB (gzip)</li>
<li>YSlow: 129KB, 39KB (gzip)</li>
</ul>
<h3>More about YSlow</h3>
<p>Keep up-to-date with the latest YSlow announcements by:</p>
<ul>
<li>Visiting the redesigned YSlow page at <a href="http://getyslow.com/">getyslow.com</a></li>
<li>Liking YSlow on Facebook: <a href="http://www.facebook.com/getyslow/">facebook.com/getyslow</a></li>
<li>Following YSlow on Twitter: <a href="http://twitter.com/getyslow/">twitter.com/getyslow</a></li>
</ul>
<p class="authorbox"><img src="http://yuiblog.com/assets/next-gen-yslow/marcel.jpg" class="alignleft" width="120" height="160" alt="Marcel Duran"><em><strong>About the author:</strong> Marcel Duran is the Front End Lead for Yahoo!&#8217;s Exceptional Performance Team. He has been into web performance optimization on high traffic sites in Yahoo! Front Page and Search teams where he applied and researched web performance best practices making pages even faster. He is now dedicated to YSlow and other performance tools development, researches and evangelism. His goal is to make the web even faster than it can be and believes there is no such thing as &#8220;just a few milliseconds won&#8217;t hurt&#8221;.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.yuiblog.com/blog/2011/07/18/next-gen-yslow-powered-by-yui/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>YUI and Loader changes for 3.4.0</title>
		<link>http://www.yuiblog.com/blog/2011/07/01/yui-and-loader-changes-for-3-4-0/</link>
		<comments>http://www.yuiblog.com/blog/2011/07/01/yui-and-loader-changes-for-3-4-0/#comments</comments>
		<pubDate>Fri, 01 Jul 2011 13:34:58 +0000</pubDate>
		<dc:creator>Dav Glass</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://www.yuiblog.com/blog/2011/06/30/</guid>
		<description><![CDATA[In 3.4.0 we started the process of shifting some of Loader&#8217;s logic around, to not only make it more performant, but to make it more robust and easier to use in other places (like on the server). We will be rolling out more changes in future revisions, but I wanted to take some time and [...]]]></description>
				<content:encoded><![CDATA[<p>In 3.4.0 we started the process of shifting some of Loader&#8217;s logic around, to not only make it more performant, but to make it more robust and easier to use in other places (like on the server). We will be rolling out more changes in future revisions, but I wanted to take some time and explain what was changed, why it was changed and how it may impact developers. For the majority of use-cases, developers will notice nothing different, except that things are a little faster and their requirement downloads are a little smaller.</p>
<h3>Seed File</h3>
<p>The first thing I want to address is the YUI seed file. In previous versions of YUI, our seed file was very tiny and did not contain Loader or any of its meta-data. We&#8217;ve found that in the 90% use-case this was not as performant as we had hoped. The normal user includes the seed file then requests their modules, which in turn means that the seed needs to first fetch Loader, then calculate all of its dependencies, then fetch them all. We now feel that this extra http request is the wrong thing to do, so the new standard seed file contains Loader and its  meta-data. Yes, this will make the initial request a little larger, but it will make the loading  of modules that much faster since all of its meta-data requirements are now already on the page.</p>
<p>If you wish to use it the old way, you can just include the yui-base seed file instead. It contains everything that is needed to make YUI run in stand-alone mode plus it contains the ability to fetch Loader on demand. If you require even finer-grained dependencies, we have created a yui-core  seed file that is exactly what the old yui-base seed was.</p>
<pre>
    /build/yui/yui-min.js //YUI Seed + Loader
    /build/yui-base/yui-base-min.js //Old YUI Seed with Loader fetch support
    /build/yui-core/yui-core-min.js //Old yui-base without Loader fetch support
</pre>
<p>It should be noted that these URLs are different than the previous URLs. Anyone that was using the <code>yui/yui-base.js</code> files need to repoint them to <code>yui-core/yui-core.js</code>. If you want the older way of loading the seed and fetching Loader, you would use the <code>yui-base/yui-base.js</code> seed file.</p>
<p>The other reasoning for this change is our roadmap for making YUI run in as many places as possible. The old seed file plus Loader in a single combo server request is all well and good if you have a combo server available in your application. <em>But what about on the server? Or in an offline app on a mobile device?</em> These places need to minimize file access while still getting the information they need.</p>
<h3>Rollups</h3>
<p>The next thing that we changed was removing rollups from the system and defaulting <strong>allowRollup</strong> to false in the Loader config. <em>What does this mean to you?</em> Well, hopefully nothing at all. Before I explain the impact of the change, let me explain the reasoning behind it. The primary reason is, again,  performance, along with payload delivery. Take this example:</p>
<pre>
     Module A: requires event-a, event-b
     Module B: requires event-c, event-d
</pre>
<p>When you request both, the rollup logic prior to 3.4.0 used to determine that you should get the <em>event</em> rollup. Which actually meant that you were getting:</p>
<pre>
     event.a, event.b, event.c, event.d, event.e, event.f, event.g, event.h
</pre>
<p>You ended up with more on your page than you actually needed. By turning off the rollup support, YUI will now ask for only what you actually requested and nothing more. In most cases, you <em>will not notice this</em>. Module developers, may run into a situation where things that worked in the past may not work now. The reason for this is that they actually worked by <em>accident</em> before. Let me use a real world example: <strong>Dial</strong>.</p>
<p>
In 3.3.0, Dial required this:
</p>
<pre>
    requires: [
        'widget',
        'dd-drag',
        'substitute',
        'event-mouseenter', 
        'transition',
        'intl'
    ]
</pre>
<p>For the most part, Dial worked in 3.4.0, however keyboard support did not work. After doing some simple investigating, it turned out that the rollup support was actually requesting the entire <strong>Event</strong> rollup (which includes event-move and event-key). Without the rollup logic pulling in all of event, 3.4.0 Dial no longer had all of its requirements. Making Dial&#8217;s requirements more specific and defining all of its actual dependencies properly makes it work as expected.</p>
<pre>
    requires: [
        'widget',
        'dd-drag',
        'substitute',
        'event-mouseenter',
        'event-move',
        'event-key',
        'transition',
        'intl'
    ]
</pre>
<p>For module developers, it is a best practice to make sure that your module requires exactly what it needs to function. Do not <strong>assume</strong> that an upstream module requirement is there. It&#8217;s always better to make sure that you ask for what you need.</p>
<p>This also means that module requirements are more well defined. For example, <code>datatype-date</code> has Intl support built in. In previous versions you would access the Intl like this:</p>
<pre>
    Y.Intl.getAvailableLangs('datatype-date');
</pre>
<p>But since this module doesn&#8217;t actually have a language (the <code>datatype-date-format</code> module does), this will fail. It needs to be more specific and actually ask for languages for the correct module:</p>
<pre>
    Y.Intl.getAvailableLangs('datatype-date-format');
</pre>
<h3>Build File Explosion and Submodule Removal</h3>
<p>After making this change, the next change we made was exploding the build directory and removing submodules from the core system. Submodule logic was not removed, only our meta-data structure was changed. This will provide backward compatibility for current installations.
<p>Submodules in the core system caused a couple of issues that we needed to resolve. The first reason was performance. Each time Loader needed to calculate dependencies, it needed to walk the submodule/plugin structure of each module. Doing this thousands of times was hurting our performance during the Loader calculate routine. By removing support for submodules in the core system we saved tens of thousands of function calls and iterations.</p>
<p>Loader was changed so that if a <code>use</code> property in a module&#8217;s meta-data defined more modules,  it will use those modules instead of trying to load the original module. So, if you requested  &#8220;<code>dd</code>&#8221; Loader would inspect &#8220;<code>dd</code>&#8220;&#8216;s meta-data and see a use property that looks something like this:</p>
<pre>
    "dd-ddm-base,dd-ddm,dd-ddm-drop,dd-drag,dd-proxy,dd-constrain,dd-drop,dd-scroll,dd-drop-plugin"
</pre>
<p>In the core YUI seed file, we are also including what we are calling <strong>virtual rollups</strong> or <strong>aliases</strong>. These module definitions are exactly the same as the meta-data in Loader. This way you can include all the files exported from our <em>Dependency Configurator</em> and still use these rollups without having Loader present on the page. In future releases, we will be refining this approach even more.</p>
<p>After making this change, we then preceeded to explode our build files. In previous releases, the submodules determined the modules file path. For example:</p>
<pre>
    "dd": {
        "submodules": {
            "dd-drag": 
            // Module data
        }
    }
</pre>
<p>In 3.3.0 when you built &#8220;dd&#8221;, the file structure looked something like this:</p>
<pre>
    /build/dd/dd-drag.js
    /build/dd/dd-ddm.js
    /build/dd/dd-drop.js
</pre>
<p>With the build system exploded in 3.4.0, &#8220;dd&#8221;&#8216;s build files now look like this:</p>
<pre>
    /build/dd-drag/dd-drag.js
    /build/dd-ddm/dd-ddm.js
    /build/dd-drop/dd-drop.js
</pre>
<p>This allowed us to remove the &#8220;path&#8221; property from all of our module meta-data as well, saving file size and reducing the logic required to assemble the modules url paths.</p>
<p><strong>If you are including a pre-configured combo URL, you must recalculate your URL when you upgrade.</strong></p>
<p>The downside to this change is that if you are including a combo URL of modules to &#8220;prep&#8221; your page you can not just change the version number and upgrade. You will need to revisit the <strong>Dependency Configurator</strong> and generate a new URL with new module structure.</p>
<h3>The Future</h3>
<p>I will be continuing to refine, refactor and maximize every aspect of our Loader and Seed strategy. These first steps were needed to aid in future changes that need to be made for not only our client-side strategy but also our server, command-line and mobile device strategies as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yuiblog.com/blog/2011/07/01/yui-and-loader-changes-for-3-4-0/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Announcing YUI Compressor 2.4.6</title>
		<link>http://www.yuiblog.com/blog/2011/04/26/yui-compressor-2-4-6/</link>
		<comments>http://www.yuiblog.com/blog/2011/04/26/yui-compressor-2-4-6/#comments</comments>
		<pubDate>Tue, 26 Apr 2011 17:09:33 +0000</pubDate>
		<dc:creator>Stoyan Stefanov</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://www.yuiblog.com/blog/?p=2973</guid>
		<description><![CDATA[We&#8217;re pleased to announce the immediate availability of version 2.4.6 of the YUI Compressor. This version contains mostly updates related to Compressor&#8217;s handling of CSS minification and introduces batch processing of multiple files with a single command. CSS minification Highlights include: Fixed numerous bugs that break the compressor and/or the resulting minified files. Added documentation [...]]]></description>
				<content:encoded><![CDATA[<p>We&#8217;re pleased to announce the immediate availability of version 2.4.6 of the <a href="http://developer.yahoo.com/yui/compressor/">YUI Compressor</a>. This version contains mostly updates related to Compressor&#8217;s handling of CSS minification and introduces batch processing of multiple files with a single command.</p>
<h3>CSS minification</h3>
<p>Highlights include:</p>
<ul>
<li>Fixed numerous bugs that break the compressor and/or the resulting minified files.</li>
<li>Added <a href="http://developer.yahoo.com/yui/compressor/css.html">documentation</a> on what exactly the minifier does and also which CSS hacks it tolerates.</li>
<li>There&#8217;s a JavaScript port of CSS min in case it&#8217;s more suitable for your build process. <a href="http://tools.w3clubs.com/cssmin/">Here&#8217;s also a test web UI</a> that uses the JavaScript port, where you can experiment with the minifier.</li>
<li>A significant number of <a href="https://github.com/yui/yuicompressor/tree/master/tests/">new tests</a> added (but you can <a href="http://developer.yahoo.com/yui/compressor/css.html#tests">add even more</a>).</li>
<li>Safe handling of some CSS features that are getting more adoption such as media queries and CSS3 transforms.</li>
</ul>
<h3>Batch processing</h3>
<p>Another welcome addition to Compressor is that it can now handle batches of files. This can significantly reduce the time your build process takes, especially if you have a great number of files to minify. </p>
<p>For example the following commands minify all <code>.js</code> and <code>.css</code> files and write the minified files with a &#8220;-min.css&#8221; suffix.</p>
<pre>$ java -jar yuicompressor.jar -o '.css$:-min.css' *.css
$ java -jar yuicompressor.jar -o '.js$:-min.js' *.js</pre>
<p>Thanks go out to <a href="http://twitter.com/ysaw">Stephen Woods</a> and the <a href="http://www.flickr.com/about/#team">Flickr team</a> for this feature!</p>
<h3>Links</h3>
<p>YUI Compressor 2.4.6 is available for immediate <a href="http://yuilibrary.com/downloads/#yuicompressor">download</a>. Feel free to help us out by <a href="http://yuilibrary.com/projects/yuicompressor/report/1">filing a bug or feature request</a>, <a href="http://developer.yahoo.com/yui/compressor/css.html#tests">writing more tests</a>, <a href="https://github.com/yui/yuicompressor">forking the code</a> or <a href="http://yuilibrary.com/forum/">joining the conversation</a>. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.yuiblog.com/blog/2011/04/26/yui-compressor-2-4-6/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Improving perceived site performance with spinners</title>
		<link>http://www.yuiblog.com/blog/2010/11/11/improving-perceived-site-performance-with-spinners/</link>
		<comments>http://www.yuiblog.com/blog/2010/11/11/improving-perceived-site-performance-with-spinners/#comments</comments>
		<pubDate>Thu, 11 Nov 2010 17:33:05 +0000</pubDate>
		<dc:creator>Matt Parker</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://www.yuiblog.com/blog/?p=2850</guid>
		<description><![CDATA[At the London Ajax meetup this week, Piotr (one of the creators of the rather good jsfiddle.net talked about spinners &#8212; the pretty common &#8220;I&#8217;m doing something&#8221; indicator &#8212; and how users perceive them. Apparently, people perceive Chrome to be faster in part because the little activity indicator keeps changing &#8212; it appears and disappears, [...]]]></description>
				<content:encoded><![CDATA[<p>At the <a href="http://www.meetup.com/londonajax/">London Ajax meetup</a> this week,  <a href="http://webdev.zalewa.info/">Piotr</a> (one of the creators of the rather good <a href="http://www.jsfiddle.net">jsfiddle.net</a> talked about spinners &mdash; the pretty common &#8220;I&#8217;m doing something&#8221; indicator &mdash; and how users perceive them.</p>
<p>Apparently, people perceive Chrome to be faster in part because the little activity indicator keeps changing &mdash; it appears and disappears, and changes speed &mdash; while a page is loading.  This sense of something happening persuades people that something is in fact happening, and faster, even if the actual speeds are identical.</p>
<p>So Piotr set up a randomized survey, comparing perceptions of load speed after clicking two buttons &mdash; it&#8217;s <a href="http://survey.jsfiddle.net/">here</a> if you&#8217;re interested.  When you click the button there&#8217;s a delay before the spinner is shown, and then a short (random) time later the results are shown.  Then you click another button, and the same thing happens.  And then you say which was faster.  He also allowed for a &#8220;this thing seems broken option&#8221;.  (If you&#8217;re going to do the survey, do it now and then come and read the conclusions &mdash; I don&#8217;t want to spoil it for you!).</p>
<p>The results are <a href="http://survey.jsfiddle.net/spinner/results/">here</a>.  The conclusion is that by delaying the display of the spinner slightly, users perceive things to be happening quicker.  But wait too long and they start to think something&#8217;s broken &mdash; 0.4s seemed to be the optimal delay, from the survey results.  And it may be worth thinking about other indicators if things take longer &mdash; add a &#8220;loading&#8230;&#8221; text overlay after 1 sec, perhaps.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yuiblog.com/blog/2010/11/11/improving-perceived-site-performance-with-spinners/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<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 [...]]]></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>9</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[Update (July 12, 2010): 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 Mobile Browser Cache Limits, Revisited. In early 2008, Wayne Shea and Tenni Theurer wrote a YUI Blog post on iPhone [...]]]></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 Ajax to [...]]]></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 [...]]]></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 [...]]]></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>
	</channel>
</rss>
