<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.yuiblog.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.yuiblog.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><!-- generator="wordpress/2.3.3" --><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/" version="2.0">

<channel>
	<title>Yahoo! User Interface Blog » Performance</title>
	<link>http://yuiblog.com/blog</link>
	<description>News and Artilces about Designing and Developing with Yahoo! Libraries.</description>
	<pubDate>Thu, 15 May 2008 15:10:39 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.3.3</generator>
	<language>en</language>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.yuiblog.com/yuiblog/performance" type="application/rss+xml" /><item>
		<title>Helping the YUI Compressor</title>
		<link>http://yuiblog.com/blog/2008/02/11/helping-the-yui-compressor/</link>
		<comments>http://yuiblog.com/blog/2008/02/11/helping-the-yui-compressor/#comments</comments>
		<pubDate>Mon, 11 Feb 2008 14:01:10 +0000</pubDate>
		<dc:creator>Nicholas C. Zakas</dc:creator>
		
		<category><![CDATA[Development]]></category>

		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://yuiblog.com/blog/2008/02/11/helping-the-yui-compressor/</guid>
		<description><![CDATA[
							

Nicholas Zakas joined Yahoo! in 2006. He is the author of Professional Ajax and Professional JavaScript for Web Developers. He&#8217;s a contributor to our Yahoo! Juku. His Maintainable JavaScript presentation is available on YUI Theater.

							
Julien’s YUI Compressor is an incredibly useful tool for decreasing the size of your JavaScript files. Since it uses Rhino to [...]]]></description>
			<content:encoded><![CDATA[<div class="interview">
<p>							<!-- optional introduction inset --></p>
<div class="intro">
<p><a href="http://www.nczonline.net/">Nicholas Zakas</a> joined Yahoo! in 2006. He is the author of <cite><a href="http://www.amazon.com/Professional-Ajax-2nd-Programmer/dp/0470109491">Professional Ajax</a></cite> and <cite><a href="http://www.amazon.com/Professional-JavaScript-Developers-Wrox-Guides/dp/0764579088/ref=sr_1_2/103-9749654-9772648?ie=UTF8&#038;s=books&#038;qid=1180057873&#038;sr=1-2">Professional JavaScript for Web Developers</a></cite>. He&#8217;s a contributor to our <a href="http://yuiblog.com/blog/2007/12/06/juku/">Yahoo! Juku</a>. His <a href="http://yuiblog.com/blog/2007/05/25/video-zakas/">Maintainable JavaScript</a> presentation is available on <a href="http://developer.yahoo.com/yui/theater/">YUI Theater</a>.</p>
</p></div>
<p>							<!-- / optional introduction inset --></p>
<p>Julien’s <a href="http://developer.yahoo.com/yui/compressor/">YUI Compressor</a> is an incredibly useful tool for decreasing the size of your JavaScript files. Since it uses <a href="http://www.mozilla.org/rhino/" title="Rhino: JavaScript for Java">Rhino</a> to parse your JavaScript code, it can perform all kinds of smart operations to save bytes in a completely safe way:</p>
<ul>
<li>Replacement of local variable names with shorter (one, two, or three character) variable names.</li>
<li>Replacement of bracket notation with dot notation where possible (i.e. <code>foo["bar"]</code> becomes <code>foo.bar</code>).</li>
<li>Replacement of quoted literal property names where possible (i.e. { <code>"foo":"bar"</code> } becomes { <code>foo:"bar"</code> } ).</li>
<li>Replacement of escaped quotes in strings (i.e. <code>'aaa\'bbb'</code> becomes <code>"aaa’bbb"</code>).</li>
</ul>
<p>Running your JavaScript code through YUI Compressor results in tremendous savings by default, but there are things you can do to increase the byte savings even further.</p>
<h3 id="use-constants-for-repeated-values">Use Constants for Repeated Values</h3>
<p>In my talk, <a href="http://yuiblog.com/blog/2007/05/25/video-zakas/">Maintainable JavaScript</a>, I talk about using constants (really, just variables that you have no intention of changing) to store repeating values. The idea is that your code is more maintainable because you have a single place to change a value instead of multiple places. As it turns out, this technique also helps YUI Compressor to remove more bytes. Consider the following function:</p>
<pre><code>function toggle(element){
    if (YAHOO.util.Dom.hasClass(element, "selected")){
        YAHOO.util.Dom.removeClass(element, "selected");
    } else {
        YAHOO.util.Dom.addClass(element, "selected");
    }
}</code></pre>
<p>This simple function is designed to toggle the “<var>selected</var>” class on a given element. If the element has the class, then it’s removed; if the element doesn’t have the class, it’s added. As a result, the string “<var>selected</var>” appears three times in the function. The function takes 212 bytes (including white space). When compressed, the resulting code is as follows:</p>
<pre><code>function toggle(A){if(YAHOO.util.Dom.hasClass(A,"selected")){YAHOO.util.Dom.removeClass(A,"selected")}else{YAHOO.util.Dom.addClass(A,"selected")}}
</code></pre>
<p>This code weighs in at 146 bytes (a savings of 30%), but you can see that the string “<var>selected</var>” still appears three times. Moving the repeated value into a variable makes the code more maintainable and allows YUI Compressor to remove extra space. Here’s the rewritten function:</p>
<pre><code>function toggle(element){
    var className = "selected";
    if (YAHOO.util.Dom.hasClass(element, className)){
        YAHOO.util.Dom.removeClass(element, className);
    } else {
        YAHOO.util.Dom.addClass(element, className);
    }
}</code></pre>
<p>This code is slightly larger than the original (241 bytes versus 212 bytes), but compresses down to the following:</p>
<pre><code>function toggle(A){var B="selected";if(YAHOO.util.Dom.hasClass(A,B)){YAHOO.util.Dom.removeClass(A,B)}else{YAHOO.util.Dom.addClass(A,B)}}
</code></pre>
<p>Note that this compressed code only has one instance of “<var>selected</var>”, resulting in a final byte size of 136 bytes, 10 bytes fewer than the previous version. The savings grow as the instances of the string increase, so if you have 20 places where “<var>selected</var>” was being used, you’d see even greater savings.</p>
<p>Replacing repeated values in your code can lead to greater incremental savings as the number of repeated values increases, as well. It is worthwhile to consider this approach not just for strings, but also for numbers (even Boolean values, if you so desire).</p>
<h3 id="store-local-references-to-objects-and-values">Store Local References to Objects/Values</h3>
<p>The YUI Compressor can’t perform variable replacement for either global variables or multi-level object references, so it’s better to store these in local variables. The previous example has three instances of <var>YAHOO.util.Dom</var> in the source code, and so the compressed version also has three instances. By storing <var>YAHOO.util.Dom</var> in a local variable, you can reduce the number of times that it appears in the compressed code. For example:</p>
<pre><code>function toggle(element){
    var className = "selected";
    var YUD = YAHOO.util.Dom;
    if (YUD.hasClass(element, className)){
        YUD.removeClass(element, className);
    } else {
        YUD.addClass(element, className);
    }
}</code></pre>
<p>This version of the function is 238 bytes, and when compressed, shows even greater savings than the previous versions of the function:</p>
<pre><code>
function toggle(A){var B="selected";var C=YAHOO.util.Dom;if(C.hasClass(A,B)){C.removeClass(A,B)}else{C.addClass(A,B)}}
</code></pre>
<p>The final weight for this version is 118 bytes, a savings of 28 bytes over the original compressed function and 120 bytes smaller from the uncompressed version. And this is just one function, imagine if you got the same savings for all functions in your script.</p>
<p>Keep in mind that this technique also applies to object properties, so if <var>className</var> were a member of an object, its value should be stored locally as well. For instance:</p>
<pre><code>function toggle(element){
    var YUD = YAHOO.util.Dom;
    if (YUD.hasClass(element, Constants.className)){
        YUD.removeClass(element, Constants.className);
    } else {
        YUD.addClass(element, Constants.className);
    }
}</code></pre>
<p>In this function, <var>Constants.className</var> contains the class to use. The variable <var>Constants</var> is global, so its name cannot be replaced. You could set up a reference to <var>Constants</var>, but that is inefficient because you’re only using one property of that object in the function, so set up a reference to <var>Constants.className</var> to save even more bytes:</p>
<pre><code>function toggle(element){
    var className = Constants.className
    var YUD = YAHOO.util.Dom;
    if (YUD.hasClass(element, className)){
        YUD.removeClass(element, className);
    } else {
        YUD.addClass(element, className);
    }
}</code></pre>
<h3 id="avoid-eval">Avoid <code>eval()</code></h3>
<p>By this point, you’ve been told that <code>eval()</code> is evil multiple times and by multiple people. YUI Compressor agrees. The nature of <code>eval()</code> is such that the code executed has access to the variables that are present in the scope in which <code>eval()</code> was called. Because of that, YUI Compressor can’t safely do variable name changing when <code>eval()</code> is present. For example:</p>
<pre><code>function doSomething(code){
    var msg = "hi";
    eval(code);
}

doSomething("alert(msg)");   //”hi”</code></pre>
<p>Even though the string that is being passed to <code>eval()</code> exists outside of the function in which <code>eval()</code> is called, it still has access to the local variables in that function. Since YUI Compressor can’t possibly know that the variable code contains a reference to a variable in the function, it doesn’t change the variable names in the <code>doSomething()</code> function, resulting in a less-than-optimal compression. Remember this: any time you use <code>eval()</code> in a function, that function’s variables cannot be renamed. The best approach is, as often said, to avoid <code>eval()</code> at all costs. If you absolutely must use <code>eval()</code> for some reason, try to isolate it away from other code so that the amount of variable renaming issues are minimal. For example:</p>
<pre><code>function myEval(code){
    return eval(code);
}

function doSomething(code){
    var msg = “hi”;
    var count= 10;

    myEval(code);
}</code></pre>
<p>In this code, the call to <code>eval()</code> is isolated away from the main body of the <code>doSomething()</code> function. Now, YUI Compressor is free to replace variables in <code>doSomething()</code>.</p>
<h3 id="avoid-width">Avoid <code>with</code></h3>
<p>The <code>with</code> statement is another that is often <a href="http://yuiblog.com/blog/2006/04/11/with-statement-considered-harmful/">recommended to avoid in JavaScript</a>. For YUI Compressor, the reason is the same for <code>eval()</code>: just the presence of <code>with</code> in a function causes variable renaming to be skipped for the entire function. There is just no way to keep track of variables versus object properties in the context of a <code>with</code> statement, so YUI Compressor rightly leaves the code as-is to avoid breaking the functionality. The best advice here is to avoid using <code>with</code> altogether. If you follow the advice of <a href="#store-local-references-to-objects-and-values">storing local copies of objects/properties</a>, you should have no use for <code>with</code>.</p>
<h3 id="use-the-verbose-option">Use the Verbose Option</h3>
<p>YUI Compressor has a “verbose” option (activated by the <code>–v</code> command line switch) that can help in the identification of some of these issues as well as a few others. The verbose option prints out warnings to the console indicating things that are preventing the YUI Compressor from fully doing its job. It will, for instance, tell you that a function contains <code>eval()</code> or the <code>with</code> statement, and therefore cannot be properly compressed. It also does analysis of variables, telling you if a variable was never defined (in which case it becomes global and cannot have its name replaced), if a variable was defined and never used (which just wastes space), and if a variable has been declared multiple times (also a waste of space).</p>
<h3 id="conclusion">Conclusion</h3>
<p>When used alone, the <a href="http://developer.yahoo.com/yui/compressor">YUI Compressor</a> achieves an excellent compression rate of your JavaScript code. The greatest byte savings are achieved by taking full advantage of variable replacement. The hints presented here have the primary goal of ensuring the YUI Compressor can do variable replacement whenever possible. Using constants to represent repeated values not only aids in compression, but also aids in the maintainability of your code by limited the number of areas that must be updated to accommodate a change in the value. Using local variables for multi-level object references allows for greater compression through variable replacement as well as providing faster runtime performance (local variable access is faster than global variable access and object property lookup). Perhaps most important is to ensure that you don’t use <code>eval()</code> or <code>with</code> when they’re not necessary, as each causes variable replacement to be turned off in the containing function. The YUI Compressor does a lot for you, but it can’t do everything. You can help it out greatly by following these tips.</p>
<p><!-- content ends here --></p></div>
]]></content:encoded>
			<wfw:commentRss>http://yuiblog.com/blog/2008/02/11/helping-the-yui-compressor/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Performance Research, Part 5: iPhone Cacheability - Making it Stick</title>
		<link>http://yuiblog.com/blog/2008/02/06/iphone-cacheability/</link>
		<comments>http://yuiblog.com/blog/2008/02/06/iphone-cacheability/#comments</comments>
		<pubDate>Wed, 06 Feb 2008 19:55:59 +0000</pubDate>
		<dc:creator>Tenni Theurer</dc:creator>
		
		<category><![CDATA[Development]]></category>

		<category><![CDATA[Performance]]></category>

		<category><![CDATA[tenni-theurer wayne-shea performance iphone cacheing op]]></category>

		<guid isPermaLink="false">http://yuiblog.com/blog/2008/02/06/iphone-cacheability/</guid>
		<description><![CDATA[

This article, co-written by Wayne Shea, is the fifth in a series of articles describing experiments conducted to learn more about optimizing web page performance (Part 1, Part 2, Part 3, Part 4). You may be wondering why you&#8217;re reading a performance article on the YUI Blog. It turns out that most of web page [...]]]></description>
			<content:encoded><![CDATA[<div class="interview">
<div class="intro">
<p>This article, co-written by Wayne Shea, is the fifth in a series of 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>). You may be wondering why you&#8217;re reading a performance article on the YUI Blog. It turns out that most of web page performance is affected by front-end engineering, that is, the user interface design and development.</p>
</p></div>
</div>
<p>At <a href="http://www.macworldexpo.com/">MacWorld 2008</a>, Steve Jobs announced that Apple sold 4 million iPhones to date, that&#8217;s 20,000 iPhones sold every day. <a href="http://marketshare.hitslink.com/report.aspx?sample=4&amp;qprid=10&amp;qpmr=14&amp;qpdt=1&amp;qpct=0&amp;qptimeframe=M&amp;qpsp=107">Net Applications</a> reports that total web browsing on iPhone is up at 0.12% for December 2007, topping the web browsing on all Windows Mobile devices combined. Apple&#8217;s iPhone has changed the game for many users browsing the web on a mobile device. Web developers can now create functionally rich and visually appealing applications that run within the iPhone&#8217;s version of the Safari Mobile web browser. While the iPhone presents new and exciting opportunities for mobile web application developers, it also provides a unique set of performance challenges.</p>
<p>Limited information is available on this device and understanding the cache properties of the browser is essential to creating a high performance web site. In earlier posts, we described how <a href="http://yuiblog.com/blog/2006/11/28/performance-research-part-1/">80% or more</a> of the end-user response time is spent on the front-end, and <a href="http://yuiblog.com/blog/2007/01/04/performance-research-part-2/">why the cache matters</a>. In this research, Yahoo!&#8217;s Exceptional Performance team investigated the iPhone cache properties and looked at how the performance rules are affected. We were particularly interested in the following cache properties on the iPhone:</p>
<ul>
<li>The maximum cache limit for an individual component.</li>
<li>The maximum cache limit for multiple components.</li>
<li>The effect of gzipped components on the maximum cache limits.</li>
<li>Whether cached components are persistent between power cycles.</a>
</ul>
<p>We conducted our cache experiments with both Apple&#8217;s iPhone and iPod Touch, and came to the same conclusions.</p>
<h3>Cache Hit or Miss?</h3>
<p>In <a href="http://yuiblog.com/blog/2007/01/04/performance-research-part-2/">Part 2</a>, we discussed the importance to differentiate between end user experiences for an empty versus a primed cache page view.</p>
<p>When an external component (scripts, stylesheets, and images) is referenced in an HTML page, the browser makes an HTTP request and stores the component in memory while the HTML page is rendered. Though components are stored in the browser&#8217;s memory during rendering, they may or may not be stored in the browser&#8217;s cache. A &#8220;cache miss&#8221; refers to when the browser bypasses the cache and requests the component over the network. A &#8220;cache hit&#8221; refers to when the component is found in the cache and the corresponding HTTP requests are avoided.</p>
<p>Components are cacheable when they include either the expires or cache-control header. </p>
<pre>
      Expires: [Expiration time in GMT Format]
      Cache-Control: max-age=[Expiration time in seconds]
</pre>
<p>Components that do not have one of the above headers will not be cached by the browser. To discover the cache capabilities on the iPhone browser and get a cache hit, we configured the server to include the following response header:</p>
<pre>
      Expires: Thu, 15 Apr 2010 20:00:00 GMT
</pre>
<h3>Maximum Cache Limits</h3>
<p>In our experiments, we varied the size of different types of components (images, stylesheets, and scripts) to determine the maximum cache size for an individual component. We found that if the size of component is greater than 25 KB, the iPhone&#8217;s browser does not cache the component. Thus, web pages designed specifically for the iPhone should reduce the size of each component to 25 Kbytes or less for optimal caching behavior.</p>
<p>The good news is if the browser downloads a component larger than 25 KB, components already in the browser cache are not affected. Components already in the cache are only replaced by newer cacheable components under 25 KB using the LRU (least recently used) algorithm.</p>
<p>Apple&#8217;s <a href="http://developer.apple.com/iphone/devcenter/designingcontent.html">website</a> indicates a 10 MB limit for individual components. The limit applies to the browser ability to store component in memory (not disk). However, the actual size that the iPhone can handle is much smaller, and depends on memory fragmentation and other applications that may be running concurrently. The uncached components are reclaimed by the browser when the page unloads.</p>
<p>To determine the maximum limit of the iPhone cache for multiple components, we incremented the number of 25 KB sized components embedded in our page. We tested the various component types and found that the iPhone browser was able to cache a maximum of 19 external 25KB components. The maximum cache limit for multiple components is found to be 475K - 500 KB. </p>
<h3>Compressed Components</h3>
<p>We also analyzed the impact of the cache characteristics on components transmitted with and without compression. We were surprised to find that the 25 KB maximum cache limit for a component is independent to whether the component was sent gzipped. The Safari browser on the iPhone decodes the component <i>before</i> saving it to the cache. Therefore, only the uncompressed size matters, which further emphasizes the importance of keeping the size of components small.</p>
<h3>The Effect of Power Cycle</h3>
<p>Every once in awhile, iPhone and iPod Touch users will need to force a hard reset, or in other words, cut the power and reboot the device. This is achieved by a hold of the sleep button for five seconds, and a simple slide to power off. Suppose a user was browsing your site at the moment before the reset. Will the images and stylesheets still be in the browser&#8217;s cache when the user returns to ensure a speedy response time when the user returns? We discovered that the iPhone browser cache is not persisted across power cycle. This means that the Safari browser cache on iPhone allocates memory from the system memory to create cached components but does not save the cached components in persistent storage. </p>
<h3>Case Study: Yahoo! Front Page</h3>
<p>Yahoo! launched a beta version of the mobile home page at the Consumer Electronics Show (CES) in January 2008. From a performance standpoint, this makes perfect sense. The iPhone has an amazing UI, but it is limited by the small cache size and slow network speed. Downloading large components over the air through the EDGE network is slower compared to DSL. According to published reports, the typical data download speed varies from 82 kbps to 150 kbps. Though the WiFi network speed is usually more acceptable, it&#8217;s better to give users the choice in which experience they&#8217;d prefer. Let&#8217;s take a closer look at the caching characteristics of the <a href="http://beta.m.yahoo.com">mobile</a> and <a href="http://www.yahoo.com">desktop</a> versions of Yahoo!&#8217;s Home Page on the iPhone. Figure 1 below shows a comparison between the two.</p>
<div>
<h4><strong>Figure 1.</strong> Yahoo! Front Page Mobile and Desktop versions on the iPhone</h4>
<p><img src="http://yuiblog.com/assets/performance/iphone-side-by-side.png" alt="Yahoo! Front Page Mobile and Desktop versions on the iPhone"></p>
</div>
<p>The desktop version of Yahoo!&#8217;s home page is roughly 11 times heavier in total size than the mobile version. As a result, the response time to load the desktop version on the iPhone is over 10 times as long. Table 1 shows a summary of the total size and number of HTTP requests to load the Yahoo!&#8217;s Front Page mobile version. Loading the page on the iPhone over the EDGE network, it took on average 2.2 seconds to load with an empty cache and on average only 1.5 seconds to load with a primed cache. Table 2 shows the desktop version took on average 25.4 seconds to load with an empty cache and on average 19.9 seconds with a primed cache. That&#8217;s 32% faster with a primed cache than empty cache to load the mobile version, rather than only 22% faster to load the desktop version. While the mobile site is designed for optimal caching behavior, the desktop version contains many more components that are uncacheable by the iPhone.</p>
<div class="figure">
<table class="chart">
<caption>Table 1. iPhone Mobile Experience</caption>
<tr>
<th></th>
<th>Empty Cache</th>
<th>Primed Cache</th>
</tr>
<tr>
<td>HTML/Text</td>
<td>5K (23K*)</td>
<td>5K (23K*)</td>
</tr>
<tr>
<td>Images</td>
<td>14K</td>
<td>5K</td>
</tr>
<tr>
<td>Total Size</td>
<td>19K (37K*)</td>
<td>10K (28K*)</td>
</tr>
<tr>
<td>HTTP Requests</td>
<td>23</td>
<td>4</td>
</tr>
<tr>
<td>Response Time</td>
<td>2.2 sec</td>
<td>1.5 sec</td>
</tr>
</table>
</div>
<div class="figure">
<table class="chart">
<caption>Table 2. iPhone Desktop Experience</caption>
<tr>
<th></th>
<th>Empty Cache</th>
<th>Primed Cache</th>
</tr>
<tr>
<td>HTML/Text</td>
<td>32K (121K*)</td>
<td>32K (121K*)</td>
</tr>
<tr>
<td>Images</td>
<td>117K</td>
<td>32K</td>
</tr>
<tr>
<td>JS/CSS</td>
<td>74K (278K*)</td>
<td>73K (272K*)</td>
</tr>
<tr>
<td>Total Size</td>
<td>223K (517K*)</td>
<td>137K (425K*)</td>
</tr>
<tr>
<td>HTTP Requests</td>
<td>30</td>
<td>4</td>
</tr>
<tr>
<td>Response Time</td>
<td>25.4 sec</td>
<td>19.9 sec</td>
</tr>
</table>
<p><strong>* </strong> Uncompressed sizes measured in kilobytes.</p>
</div>
<h3>Takeaways</h3>
<p>Design sites specific for iPhone users. In addition to improved usability, you will also reduce the overall page weight and enhance end-user&#8217;s performance. Yahoo!&#8217;s Exceptional Performance team identified <a href="http://developer.yahoo.com/performance/rules.html">13 rules for making web pages fast</a>. The iPhone cache experiment suggests an additional performance rule specific for developing web sites for the iPhone:</p>
<h4>Reduce the size of each component to 25 Kbytes or less for optimal caching behavior.</h4>
<p>Given that the wireless network speed on iPhone is limited and the browser cache is cleared across power cycle, it is even more important to make fewer HTTP requests to achieve good performance than in the desktop world. To reduce the number of HTTP requests, Safari on iPhone supports image map, CSS sprites, inline images and inline CSS images. Take advantage of the browser cache whenever possible. If an external component can be shared across multiple pages in the site, remember that each individual component has to be smaller than 25 KB to be cacheable. Also, the maximum cache limit of all components is 475 - 500 KB. Minify all the JavaScript, CSS and HTML. For components that aren&#8217;t shared across multiple pages, consider making them inline.</p>
]]></content:encoded>
			<wfw:commentRss>http://yuiblog.com/blog/2008/02/06/iphone-cacheability/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Hosting YUI Files for Implementations in Mainland China</title>
		<link>http://yuiblog.com/blog/2008/01/15/hosting-yui-in-china/</link>
		<comments>http://yuiblog.com/blog/2008/01/15/hosting-yui-in-china/#comments</comments>
		<pubDate>Tue, 15 Jan 2008 16:54:31 +0000</pubDate>
		<dc:creator>Eric Miraglia</dc:creator>
		
		<category><![CDATA[Development]]></category>

		<category><![CDATA[Performance]]></category>

		<category><![CDATA[china]]></category>

		<category><![CDATA[hosting]]></category>

		<category><![CDATA[yui]]></category>

		<guid isPermaLink="false">http://yuiblog.com/blog/2008/01/15/hosting-yui-in-china/</guid>
		<description><![CDATA[Back in February 2007, we opened up hosting of YUI files on Yahoo&#8217;s content delivery network to all users, and we maintain a page describing how you can implement YUI while drawing all of its resources from our network.  What we&#8217;ve heard from the YUI community is that having this choice is a big [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.yuiblog.cn/2008/01/14/yui%e6%9c%ac%e5%9c%b0%e7%89%88%e5%8f%91%e5%b8%83/"><img src="http://yuiblog.com/assets/yuiblog.cn.png" align="right" alt="Announcing support for hosting YUI in China on YUIBlog.cn" height="202" width="300" border="0" hspace="10" vspace="5"></a>Back in February 2007, we opened up hosting of YUI files on Yahoo&#8217;s content delivery network to all users, and we maintain a page describing <a href="http://developer.yahoo.com/yui/articles/hosting/">how you can implement YUI while drawing all of its resources from our network</a>.  What we&#8217;ve heard from the YUI community is that having this choice is a big deal &mdash; and more than a billion YUI files were served from our <code>yui.yahooapis.com</code> last week, a number that has grown steadily since we opened up that service.</p>
<p>The <code>yui.yahooapis.com</code> domain is an edge-hosted CDN, and it automatically draws files from data centers as close as possible to the source of the request, optimizing performance.  While that works well in most locations, one area where we were seeing poor response times was in China, where a growing community of YUI users is located.  To help improve performance for implementers serving the China market, we&#8217;re announcing today the availability of <code>cn.yui.yahooapis.com</code>, a CDN specifically for that region.
<p>As of today, the following two paths will both work for retrieving the minified <a href="http://developer.yahoo.com/yui/yahoo/">Yahoo Global Object</a>:</p>
<ul>
<li><a href="http://cn.yui.yahooapis.com/2.4.1/build/yahoo/yahoo-min.js">http://cn.yui.yahooapis.com/2.4.1/build/yahoo/yahoo-min.js</a> (China region)</li>
<li><a href="http://yui.yahooapis.com/2.4.1/build/yahoo/yahoo-min.js">http://yui.yahooapis.com/2.4.1/build/yahoo/yahoo-min.js</a> (standard, global usage)</li>
</ul>
<p>For most implementations, you&#8217;ll want to continue using the standard <code>yui.yahooapis.com</code>, but if your project serves China primarily the new domain will improve your response times and deliver a better experience.  For users in mainland China, we&#8217;ve seen as much as a 5x improvement in response times based on initial tests.</p>
<p>A bit more about this (in Chinese) on <a href="http://www.yuiblog.cn/2008/01/14/yui%e6%9c%ac%e5%9c%b0%e7%89%88%e5%8f%91%e5%b8%83/">YUIBlog.cn</a>, a blog created recently by the user experience team at Yahoo! China (a company in the Alibaba group). A big thanks to Hongwei Zeng, an engineer at Yahoo! China, for helping to make this arrangement possible.</p>
]]></content:encoded>
			<wfw:commentRss>http://yuiblog.com/blog/2008/01/15/hosting-yui-in-china/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Performance Research, Part 4: Maximizing Parallel Downloads in the Carpool Lane</title>
		<link>http://yuiblog.com/blog/2007/04/11/performance-research-part-4/</link>
		<comments>http://yuiblog.com/blog/2007/04/11/performance-research-part-4/#comments</comments>
		<pubDate>Wed, 11 Apr 2007 19:47:01 +0000</pubDate>
		<dc:creator>Tenni Theurer</dc:creator>
		
		<category><![CDATA[Development]]></category>

		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://yuiblog.com/blog/2007/04/11/performance-research-part-4/</guid>
		<description><![CDATA[

This article, co-written by Steve Souders, is the fourth in a series of articles describing experiments conducted to learn more about optimizing web page performance (Part 1, Part 2, Part 3). You may be wondering why you&#8217;re reading a performance article on the YUI Blog. It turns out that most of web page performance is [...]]]></description>
			<content:encoded><![CDATA[<div class="interview">
<div class="intro">
<p>This article, co-written by <a href="http://stevesouders.com/bio.html">Steve Souders</a>, is the fourth in a series of 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>). You may be wondering why you&#8217;re reading a performance article on the YUI Blog. It turns out that most of web page performance is affected by front-end engineering, that is, the user interface design and development.</p>
</p></div>
</div>
<h3 id="parallel-downloads">Parallel Downloads</h3>
<p>The biggest impact on end-user response times is the number of components in the page. Each component requires an extra HTTP request, perhaps not when the cache is full, but definitely when the cache is empty. Knowing that the browser performs HTTP requests in parallel, you may ask why the number of HTTP requests affects response time. Can&#8217;t the browser download them all at once?</p>
<p>The explanation goes back to the HTTP/1.1 spec, which suggests that browsers download two components in parallel per hostname. Many web pages download all their components from a single hostname. Viewing these HTTP requests reveals a stair-step pattern, as shown in Figure 1.</p>
<div class="chart" id="figure-1">
<h4><strong>Figure 1.</strong> Downloading 2 components in parallel</h4>
<p><img src="http://yuiblog.com/assets/performance/two_parallel.gif" alt="Figure 1. Downloading 2 components in parallel" width="311" height="200" longdesc="two_parallel.gif" id="two_parallel"></p>
</div>
<p>If a web page evenly distributed its components across two hostnames, the overall response time would be about twice as fast. The HTTP requests would look as shown in Figure 2, with four components downloaded in parallel (two per hostname). The horizontal width of the box is the same, to give a visual cue as to how much faster this page loads.</p>
<div class="chart" id="figure-2">
<h4><strong>Figure 2.</strong> Downloading 4 components in parallel</h4>
<p><img src="http://yuiblog.com/assets/performance/four_parallel.gif" alt="Figure 2. Downloading 4 components in parallel" width="311" height="200" longdesc="four_parallel.gif" id="four_parallel"></p>
</div>
<p>Limiting parallel downloads to two per hostname is a guideline. By default, both Internet Explorer and Firefox follow the guideline, but users can override this default behavior. Internet Explorer stores the value in the Registry Editor. (See <a href="http://support.microsoft.com/?kbid=282402">Microsoft Help and Support</a>.) Firefox&#8217;s setting is controlled by the <span style="color:red">network.http.max-persistent-connections-per-server</span> setting, accessible in the about:config page.</p>
<p>It&#8217;s interesting to note that for HTTP/1.0, Firefox&#8217;s default is to download eight components in parallel per hostname. Figure 3 shows what it would look like to download these ten images if Firefox&#8217;s HTTP/1.0 settings are used. It&#8217;s even faster than Figure 2, and we didn&#8217;t have to split the images across two hostnames.</p>
<div class="chart" id="figure-3">
<h4><strong>Figure 3.</strong> Downloading 8 components in parallel</h4>
<p><img src="http://yuiblog.com/assets/performance/eight_parallel.gif" alt="Figure 3. Downloading 8 components in parallel" width="311" height="200" id="eight_parallel"></p>
</div>
<p>Most web sites today use HTTP/1.1, but the idea of increasing parallel downloads beyond two per hostname is intriguing. Instead of relying on users to modify their browser settings, front-end engineers could simply use CNAMEs (DNS aliases) to split their components across multiple hostnames. Maximizing parallel downloads doesn&#8217;t come without a cost. Depending on your bandwidth and CPU speed, too many parallel downloads can degrade performance.</p>
<p>If browsers limit the number of parallel downloads to two (per hostname over HTTP/1.1), this raises the question:</p>
<h3 id="what-if">What if we use additional aliases to increase parallel downloads in our pages?</h3>
<p>We&#8217;ve seen a couple great blogs and articles written recently on the subject, most notably <a href="http://www.ajaxperformance.com/?p=33">Ryan Breen of Gomez</a> and <a href="http://www.die.net/musings/page_load_time/">Aaron Hopkins over at Google</a>. Here&#8217;s another spin. The performance team at Yahoo! ran an experiment to measure the impact of using various numbers of hostname aliases. The experiment measured an empty HTML document with 20 images on the page. The images were fetched from the same servers as those used by real Yahoo! pages. We ran the experiment in a controlled environment using a test harness that fetches a set of URLs repeatedly while measuring how long it takes to load the page on DSL. The results are shown in Figure 4.</p>
<div class="chart" id="figure-4">
<h4><strong>Figure 4.</strong> Loading an Empty HTML Document with 20 images using Various Number of Aliases</h4>
<p><img src="http://yuiblog.com/assets/performance/expt.gif" alt="Figure 4. Loading an Empty HTML Document with 20 images using Various Number of Aliases" width="576" height="386" id="expt"></p>
<p class="gloss"><strong>Note: </strong> Times are for cached aliases, empty file cache page loads on DSL (~800 kbps).</p>
</div>
<p>In our experiment, we vary the number of aliases: 1, 2, 4, 5, and 10. This increases the number of parallel downloads to 2, 4, 8, 10, and 20 respectively. We fetch 20 smaller-sized images (36 x 36 px) and 20 medium-sized images (116 x 61 px). To our surprise, increasing the number of aliases for loading the medium-size images (116 x 61px) worsens the response times using four or more aliases. Increasing the number of aliases by more than two for smaller-sized images (36 x 36px) doesn&#8217;t make much of an impact on the overall response time. On average, using two aliases is best.</p>
<p>One possible contributor for slower response times is the amount of CPU thrashing on the client caused by increasing the number of parallel downloads. The more images that are downloaded in parallel, the greater the amount of CPU thrashing on the client. On my laptop at work, the CPU jumped from 25% usage for 2 parallel downloads to 40% usage for 20 parallel downloads. These values can vary significantly across users&#8217; computers but is just another factor to consider before increasing the number of aliases to maximize parallel downloads.</p>
<p>These results are for the case where the domains are already cached in the browser. In the case where the domains are not cached, the response times get significantly worse as the number of hostname aliases increases. For web pages desiring to optimize the experience for first time users, we recommend not to increase the number of domains. To optimize for the second page view, where the domains are most likely cached, increasing parallel downloads does improve response times. The choice depends on which scenario was most typical.</p>
<p>Another issue to consider is that DNS lookup times vary significantly across ISPs and geographic locations. Typically, DNS lookup times for users from non-US cities are significantly higher than those for users within the US. If a good percentage of your users are coming from outside the US, the benefits of increasing parallel downloads is offset by the time to make many DNS lookups.</p>
<p>Our rule of thumb is to increase the number of parallel downloads by using at least two, but no more than four hostnames. Once again, this underscores the number one rule for improving response times: reduce the number of components in the page. </p>
<div class="interview">
<div class="intro">
<p>Steve Souders is also writing a series of blogs on <a href="http://developer.yahoo.com">Yahoo! Developer Network</a> describing best practices he&#8217;s developed at Yahoo! for improving performance (<a href="http://developer.yahoo.net/blog/archives/2007/03/high_performanc.html">Part 1</a>, <a href="http://developer.yahoo.net/blog/archives/2007/04/rule_1_make_few.html">Part 2</a>).</p>
</p></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://yuiblog.com/blog/2007/04/11/performance-research-part-4/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Performance Research, Part 3: When the Cookie Crumbles</title>
		<link>http://yuiblog.com/blog/2007/03/01/performance-research-part-3/</link>
		<comments>http://yuiblog.com/blog/2007/03/01/performance-research-part-3/#comments</comments>
		<pubDate>Fri, 02 Mar 2007 00:41:59 +0000</pubDate>
		<dc:creator>Tenni Theurer</dc:creator>
		
		<category><![CDATA[Development]]></category>

		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://yuiblog.com/blog/2007/03/01/performance-research-part-3/</guid>
		<description><![CDATA[

This article, co-written by Patty Chi, is the third in a series of articles describing experiments conducted to learn more about optimizing web page performance (Part 1, Part 2). You may be wondering why you&#8217;re reading a performance article on the YUI Blog. It turns out that most of web page performance is affected by [...]]]></description>
			<content:encoded><![CDATA[<div class="interview">
<div class="intro">
<p>This article, co-written by Patty Chi, is the third in a series of 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>). You may be wondering why you&#8217;re reading a performance article on the YUI Blog. It turns out that most of web page performance is affected by front-end engineering &mdash; that is, the user interface design and development.</p>
</p></div>
</p></div>
<p>HTTP cookies are used for a variety of reasons such as authentication and personalization. Information about cookies is exchanged in the HTTP headers between web servers and browsers. This article discusses the impact of cookies on the overall user response time.</p>
<h3 id="http-quick-review">HTTP Quick Review</h3>
<p>Cookies originate from web servers when browsers request a page. Here is a sample HTTP header sent by the web server after a request for <code>www.yahoo.com</code>:</p>
<pre>
  HTTP/1.1 200 OK
  Content-Type: text/html; charset=utf-8
  Set-Cookie: C=abcde; path=/; domain=.yahoo.com
</pre>
<p>The header includes information about the response such as the protocol version, status code, and content-type. The <code>Set-Cookie</code> is also included in the response and in this example the name of the cookie is &#8220;C&#8221; and the value of the cookie is &#8220;abcde&#8221;. Note: The maximum size of a cookie is 5051 bytes in IE 6.0 and 4096 bytes in Firefox 1.5.</p>
<p>The browser saves the &#8220;C&#8221; cookie on the user&#8217;s computer and sends it back in future requests. The &#8220;<code>domain=.yahoo.com</code>&#8221; specifies that the browser should include the cookie in future requests within the <code>.yahoo.com</code> domain and all its sub-domains. For example, if the user then visits <code>finance.yahoo.com</code>, the browser includes the &#8220;C&#8221; cookie in the request. Since an Expires attribute is not included in this example, the cookie expires at the end of the session.</p>
<p>Here is a sample HTTP header for <code>finance.yahoo.com</code> sent by the browser:</p>
<pre>
  GET / HTTP/1.1
  Host: finance.yahoo.com
  User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; ...
  Cookie: C=abcde;
</pre>
<p>Notice that the &#8220;C&#8221; cookie, originating from <code>www.yahoo.com</code>, is also included in the request for <code>finance.yahoo.com</code>.</p>
<h3 id="impact-on-response-time">Impact of cookies on response time</h3>
<p id="table1">The performance team at Yahoo! ran an experiment to measure the impact of retrieving a document with various cookie sizes. The experiment measured a static HTML document with no elements in the page. The primary variable in the experiment was the cookie size. We ran the experiment using a test harness that fetches a set of URLs repeatedly while measuring how long it takes to load the page on DSL. The results are shown in Table 1.</p>
<div class="figure" id="response-times-for-various-cookie-sizes-figure">
<table class="chart" id="response-times-for-various-cookie-sizes-table">
<caption>Table 1. Response times for various cookie sizes</caption>
<tr>
<th>Cookie Size</th>
<th>Median Response Time (Delta)</th>
</tr>
<tr>
<td>0 bytes</td>
<td>78 ms (<b>0 ms</b>)</td>
</tr>
<tr>
<td>500 bytes</td>
<td>79 ms (<b>+1 ms</b>)</td>
</tr>
<tr>
<td>1000 bytes</td>
<td>94 ms (<b>+16 ms</b>)</td>
</tr>
<tr>
<td>1500 bytes</td>
<td>109 ms (<b>+31 ms</b>)</td>
</tr>
<tr>
<td>2000 bytes</td>
<td>125 ms (<b>+47 ms</b>)</td>
</tr>
<tr>
<td>2500 bytes</td>
<td>141 ms (<b>+63 ms</b>)</td>
</tr>
<tr>
<td>3000 bytes</td>
<td>156 ms (<b>+78 ms</b>)</td>
</tr>
</table>
<p class="gloss"><strong>Note: </strong> Times are for page loads on DSL (~800 kbps).</p>
</div>
<p>These results highlight the importance of keeping the size of cookies as low as possible to minimize the impact on the user&#8217;s response time. A 3000 byte cookie, or multiple cookies that total 3000 bytes, could add as much as an 80 ms delay for users on DSL bandwidth speeds. The delay is even worse for users on dial-up.</p>
<h3 id="how-big-at-yahoo">How big are users&#8217; cookies set at the .yahoo.com domain?</h3>
<p>Cookies set at the <code>.yahoo.com</code> domain affect the overall response time for users visiting web pages across the Yahoo! network. Figure 1 shows the percentages of Yahoo!&#8217;s total page views with various cookie sizes set at the <code>.yahoo.com</code> domain.</p>
<div class="chart">
<h4 id="percent-of-views-with-cookie-sizes"><strong>Figure 1.</strong> Percentage of Page Views with Various Cookie Sizes</h4>
<p><img src="http://www.yuiblog.com/assets/performance/cookies.gif" alt="Figure 1. Percentage of Page Views with Various Cookie Sizes" width="505" height="304" id="cookies"/></p>
</div>
<p>About 80% of page views have fewer than 1000 bytes of cookies, which correlates to about a 5 to 15 ms delay for users on DSL bandwidth speeds. While the data shows that the majority of page views aren&#8217;t impacted by a significant delay, it also shows that about 2% of page views have over 1500 bytes of cookies set at the <code>.yahoo.com</code> domain. Although 2% sounds insignificant, at Yahoo! this translates to millions of page views per day, a compelling motivation for us to investigate this 2% and eliminate unnecessary cookies, reduce cookie sizes, and set cookies at more granualar domain levels.</p>
<p>In an earlier post about browser cache usage, one user made a <a href="http://yuiblog.com/blog/2007/01/04/performance-research-part-2/#comment-29021">comment</a> about the side-effects of different browsers. Since Internet Explorer and Firefox have different implementations for the maximum size and number of cookies supported, we also analyzed the data by browser type and found no significant difference between the cookie sizes. It would be interesting to further investigate whether there is a difference in performance across browsers.</p>
<h3 id="how-big-across-the-web">Analysis of Cookie Sizes across the Web</h3>
<p id="table2">To show how Yahoo!&#8217;s cookie usage relates to those of other companies, we analyzed the cookies set by other popular web sites. For this experiment, we cleared all our cookies and visited only the home pages of these web sites. Table 2 shows between 60 and 500 bytes of cookie information included in the HTTP headers.</p>
<div class="figure" id="total-cookie-sizes-figure">
<table class="chart" id="total-cookie-sizes-chart">
<caption>Table 2. Total Cookie Sizes</caption>
<tr>
<td>&nbsp;</td>
<th>Total Cookie Size</th>
</tr>
<tr>
<th><a href="http://www.amazon.com/">Amazon</a></th>
<td>60 bytes</td>
</tr>
<tr>
<th><a href="http://www.google.com/">Google</a></th>
<td>72 bytes</td>
</tr>
<tr>
<th><a href="http://www.yahoo.com/">Yahoo</a></th>
<td>122 bytes</td>
</tr>
<tr>
<th><a href="http://www.cnn.com/">CNN</a></th>
<td>184 bytes</td>
</tr>
<tr>
<th><a href="http://www.youtube.com/">YouTube</a></th>
<td>218 bytes</td>
</tr>
<tr>
<th><a href="http://www.msn.com/">MSN</a></th>
<td>268 bytes</td>
</tr>
<tr>
<th><a href="http://www.ebay.com/">eBay</a></th>
<td>331 bytes</td>
</tr>
<tr>
<th><a href="http://www.myspace.com/">MySpace</a></th>
<td>500 bytes</td>
</tr>
</table>
<p class="gloss"><strong>Note: </strong> We only requested the home page.</p>
</div>
<p>The data in Table 2 reflects only cookies set at the top domain levels to eliminate any cookies that may have been set by ads. The total cookie size for Yahoo! (122 bytes) in Table 2 differs from the cookie sizes indicated in Figure 4 because in this experiment we visited only the home pages of each web site. The data in Figure 4 reflect real users, many of whom visit multiple Yahoo! web pages. To illustrate, if <code>tv.yahoo.com</code> and <code>movies.yahoo.com</code> wanted to share information within a cookie, the cookie must be set at the <code>.yahoo.com</code> domain. The total cookie size set at the <code>.yahoo.com</code> domain for a user who visits multiple Yahoo! sub-domains is typically higher than the total cookie size set for a user who only visits <code>www.yahoo.com</code>.</p>
<p>Setting cookies at the appropriate path and domain is just as important as the size of the cookie, if not more. A cookie set at the <code>.yahoo.com</code> domain impacts the response time for every Yahoo! page in the <code>.yahoo.com</code> domain that a user visits.</p>
<h3 id="takeaways">Takeaways</h3>
<ul>
<li>Eliminate unnecessary cookies.</li>
<li>Keep cookie sizes as low as possible to minimize the impact on the user response time. </li>
<li>Be mindful of setting cookies at the appropriate domain level so other sub-domains are not affected.</li>
<li>Set an Expires date appropriately. An earlier Expires date or none removes the cookie sooner, improving the user response time.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://yuiblog.com/blog/2007/03/01/performance-research-part-3/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Performance Research, Part 2: Browser Cache Usage - Exposed!</title>
		<link>http://yuiblog.com/blog/2007/01/04/performance-research-part-2/</link>
		<comments>http://yuiblog.com/blog/2007/01/04/performance-research-part-2/#comments</comments>
		<pubDate>Thu, 04 Jan 2007 20:24:11 +0000</pubDate>
		<dc:creator>Tenni Theurer</dc:creator>
		
		<category><![CDATA[Development]]></category>

		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://yuiblog.com/blog/2007/01/04/performance-research-part-2/</guid>
		<description><![CDATA[

This is the second in a series of articles describing experiments conducted to learn more about optimizing web page performance. You may be wondering why you&#8217;re reading a performance article on the YUI Blog. It turns out that most of web page performance is affected by front-end engineering, that is, the user interface design and [...]]]></description>
			<content:encoded><![CDATA[<div>
<div>
<p>This is the second in a series of articles describing experiments conducted to learn more about optimizing web page performance. You may be wondering why you&#8217;re reading a performance article on the YUI Blog. It turns out that most of web page performance is affected by front-end engineering, that is, the user interface design and development.</p>
</p></div>
</div>
<p>In an earlier post, I described <a href="http://yuiblog.com/blog/2006/11/28/performance-research-part-1/">What the 80/20 Rule Tells Us about Reducing HTTP Requests</a>. Since browsers spend 80% of the time fetching external components including scripts, stylesheets and images, reducing the number of HTTP requests has the biggest impact on reducing response time. But shouldn&#8217;t everything be saved in the browser&#8217;s cache anyway?</p>
<h3>Why does cache matter?</h3>
<p>It&#8217;s important to differentiate between end user experiences for an empty versus a full cache page view. An &#8220;empty cache&#8221; means the browser bypasses the disk cache and has to request all the components to load the page. A &#8220;full cache&#8221; means all (or at least most) of the components are found in the disk cache and the corresponding HTTP requests are avoided.</p>
<p>The main reason for an empty cache page view is because the user is visiting the page for the first time and the browser has to download all the components to load the page. Other reasons include:</p>
<ul>
<li>The user visited the page previously but cleared the browser cache.</li>
<li>The browser cache was automatically cleared, based on the browser&#8217;s settings.</li>
<li>The user reloaded the page in a way that caused the cache to be bypassed. For example, the browser will bypass the cache if you hold down the control-shift key while clicking the Refresh button in Internet Explorer. </li>
</ul>
<p>Strategies such as combining scripts, stylesheets, or images reduce the number of HTTP requests for <i>both</i> an empty and a full cache page view. Configuring components to have an Expires header with a date in the future reduces the number of HTTP requests for only the full cache page view.</p>
<p>Previously, we observed where the time is spent when a user requests <a href="http://www.yahoo.com">http://www.yahoo.com</a> with an empty cache. When a user loads the page, the browser downloads approximately 30 components (see Figure 1). Figure 2 is a graphical view of where the time is spent loading <a href="http://www.yahoo.com">http://www.yahoo.com</a> with a full cache. Each bar represents a specific component requested by the browser. Since components are already in the cache on a full cache page view, and the Expires header has a date in the future, the browser only has to download three components including the HTML document</p>
<div>
	<img src="http://yuiblog.com/assets/performance/pageload-empty.gif" alt="Figure 1. Loading http://www.yahoo.com with an empty cache" width="500" height="355" longdesc="Chart in picture shows linear loading of approximately 30 components required by yahoo.com homepage."></p>
<h4>Figure 1. Loading http://www.yahoo.com with an empty cache</h4>
</div>
<div>
	<img src="http://yuiblog.com/assets/performance/pageload-full.gif" alt="Figure 2. Loading http://www.yahoo.com with a full cache" width="500" height="90" longdesc="This chart shows that only 3 components are necessary when the user has the other resources in cache."></p>
<h4>Figure 2. Loading http://www.yahoo.com with a full cache</h4>
</div>
<p>Table 1 shows a summary of the total size and number of requests for each type of component to load <a href="http://www.yahoo.com">http://www.yahoo.com</a>. How much does a full cache benefit the user? Loading the page over my cable modem at home, it took 2.4 seconds with an empty cache and only 0.9 seconds with a full cache. The full cache page view had 90% fewer HTTP requests and 83% fewer bytes to download than the empty cache page view.</p>
<div>
<h4>Table 1. Empty and Full Cache Summary to load http://www.yahoo.com</h4>
<p>	<img src="http://yuiblog.com/assets/performance/empty-full.gif" alt="Table 1. Empty and Full Cache Summary to load http://www.yahoo.com" width="485" height="157"></p>
<p>* Times were measured over cable modem (~2.5 mbps).</p>
</div>
<h3>How many users view Yahoo! pages with a full cache?</h3>
<p>The performance team at Yahoo! ran an experiment to determine the percentage of users and page views with an empty cache on some of Yahoo!&#8217;s most popular pages. We defined the experiment to measure users&#8217; cache behavior related to a new component (an image). For this new image we measured the following statistics each day:</p>
<ol>
<li>What percentage of users requested the new image?</li>
<li>What percentage of page views requested the new image?</li>
</ol>
<p>The new image was configured with the following HTTP headers:</p>
<pre>
Expires: Thu, 15 Apr 2004 20:00:00 GMT
Last-Modified: Wed, 28 Sep 2006 23:49:57 GMT
</pre>
<p>When the browser saves a component in its cache, it also saves the Expires and Last Modified values. Specifying an Expires date in the past forces the browser to request the image every time the page is viewed (with a few exceptions, such as when users click the browser&#8217;s &#8220;back&#8221; button to return to a page). If the image is already in the browser&#8217;s cache and is being re-requested, the browser will pass the Last-Modified date in the request header. This is called a <i>conditional GET request</i> and if the image has not been modified, the server will return a <code>304 Not Modified</code> response. The requests from browsers, therefore, result in one of the following response status codes:</p>
<ul>
<li>200 &#8212; The browser does not have the image in its cache.</li>
<li>304 &#8212; The browser has the image in its cache, but needs to verify the last modified date.</li>
</ul>
<p>Since the status codes are recorded in the apache access logs, we are able to determine the empty and full cache measurements by analyzing the logs.</p>
<p>The percentage of users with an empty cache is:</p>
<pre>
       # of unique users with at least one 200 response
      <s>                                                  </s>
                    total # of unique users
</pre>
<p>The percentage of page views with an empty cache is:</p>
<pre>
                      # of 200 responses
          <s>                                         </s>
           # of 200 responses + # of 304 responses
</pre>
<p>Figure 3 shows the percentage of users and page views with an empty cache plotted over each day of the experiment. On the first day of the experiment, no one had these images cached so the empty cache percentage was 100%. As the days passed more users had the images cached, so the percentages dropped until at some point it reached a constant steady state.</p>
<div>
	<img src="http://yuiblog.com/assets/performance/cache-expt.gif" alt="Figure 3. Percentage of Users and Page Views with an Empty Cache"></p>
<h4>Figure 3. Percentage of Users and Page Views with an Empty Cache</h4>
</div>
<h3>Suprising Results</h3>
<p>40-60% of Yahoo!&#8217;s users have an empty cache experience and ~20% of all page views are done with an empty cache. To my knowledge, there&#8217;s no other research that shows this kind of information. And I don&#8217;t know about you, but these results came to us as a <i>big</i> surprise. It says that even if your assets are optimized for maximum caching, there are a significant number of users that will <i>always</i> have an empty cache. This goes back to the earlier point that reducing the number of HTTP requests has the <i>biggest</i> impact on reducing response time. The percentage of users with an empty cache for different web pages may vary, especially for pages with a high number of active (daily) users. However, we found in our study that regardless of usage patterns, the percentage of page views with an empty cache is always ~20%.</p>
<p>Conclusion: Keep in mind the empty cache user experience. It might be more prevalent than you think!</p>
]]></content:encoded>
			<wfw:commentRss>http://yuiblog.com/blog/2007/01/04/performance-research-part-2/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Performance Research, Part 1:  What the 80/20 Rule Tells Us about Reducing HTTP Requests</title>
		<link>http://yuiblog.com/blog/2006/11/28/performance-research-part-1/</link>
		<comments>http://yuiblog.com/blog/2006/11/28/performance-research-part-1/#comments</comments>
		<pubDate>Tue, 28 Nov 2006 20:56:47 +0000</pubDate>
		<dc:creator>Tenni Theurer</dc:creator>
		
		<category><![CDATA[Development]]></category>

		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://yuiblog.com/blog/2006/11/28/performance-research-part-1/</guid>
		<description><![CDATA[

This is the first in a series of articles describing experiments conducted to learn more about optimizing web page performance. You may be wondering why you&#8217;re reading a performance article on the YUI Blog. It turns out that most of web page performance is affected by front-end engineering, that is, the user interface design and [...]]]></description>
			<content:encoded><![CDATA[<div class="interview">
<div class="intro">
<p>This is the first in a series of articles describing experiments conducted to learn more about optimizing web page performance. You may be wondering why you&#8217;re reading a performance article on the YUI Blog. It turns out that most of web page performance is affected by front-end engineering, that is, the user interface design and development.</p>
</p></div>
</div>
<p>It&#8217;s no secret that users prefer faster web sites.  I work in a dedicated team focused on quantifying and improving the performance of Yahoo! products worldwide.  As part of our work, we conduct experiments related to web page performance.  We are sharing our findings so that other front-end engineers join us in accelerating the user experience on the web.</p>
<h3 id="the-80-20-rule">The 80/20 Performance Rule</h3>
<p id="pareto">Vilfredo Pareto, an economist in the early 1900s, made a famous observation where 80% of the nation&#8217;s wealth belonged to 20% of the population.  This was later generalized into what&#8217;s commonly referred to as the Pareto principle (also known as the 80-20 rule), which states for any phenomenon, 80% of the consequences come from 20% of the causes.  We see this phenomenon in software engineering where 80% of the time is spent in only 20% of the code.  When we optimize our applications, we know to focus on that 20% of the code.  This same technique should also be applied when optimizing web pages.  Most performance optimization today are made on the parts that generate the HTML document (apache, C++, databases, etc.), but those parts only contribute to about 20% of the user&#8217;s response time.  It&#8217;s better to focus on optimizing the parts that contribute to the other 80%.</p>
<p id="figure1">Using a packet sniffer, we discover what takes place in that other 80%.  Figure 1 is a graphical view of where the time is spent loading http://www.yahoo.com with an empty cache.  Each bar represents a specific component and is shown in the order started by the browser.  The first bar is the time spent for the browser to retrieve just the HTML document.  Notice only 10% of the time is spent here for the browser to request the HTML page, and for apache to stitch together the HTML and return the response back to the browser.  The other 90% of the time is spent fetching other components in the page including images, scripts and stylesheets. </p>
<div class="figure">
<h4 class="caption">Figure 1. Loading http://www.yahoo.com</h4>
<p>	<img class="figure" src="http://yuiblog.com/assets/performance/pageload.gif" alt="Figure 1. Loading http://www.yahoo.com" width="500" height="355" id="pageload" longdesc="This image is a chart showing the sequential loading of the 29 components that make up the yahoo.com homepage. The first component is the html itself, and which only takes 0.24 seconds. The remaining 28 items are images, scripts, and stylesheets. The takeaway from the graphic is that nearly all the time is on subsequent requests, not the initial server response.">
</div>
<p id="table1">Table 1 shows popular web sites spending between 5% and 38% of the time downloading the HTML document. The other 62% to 95% of the time is spent making HTTP requests to fetch all the components in that HTML document (i.e. images, scripts, and stylesheets).  The impact of having many components in the page is exacerbated by the fact that browsers download only two or four components in parallel per hostname, depending on the HTTP version of the response and the user&#8217;s browser.  Our experience shows that reducing the number of HTTP requests has the biggest impact on reducing response time and is often the easiest performance improvement to make.</p>
<div class="figure" id="loading-popular-web-sites">
<table class="chart" id="time-spent-loading-popular-web-sites">
<caption>Table 1. Time spent loading popular web sites</caption>
<tr>
<td class="empty">&nbsp;</td>
<th>Time Retrieving HTML</th>
<th>Time Elsewhere</th>
</tr>
<tr>
<th>Yahoo!</th>
<td>10%</td>
<td>90%</td>
</tr>
<tr>
<th>Google</th>
<td>25%</td>
<td>75%</td>
</tr>
<tr>
<th>MySpace</th>
<td>9%</td>
<td>91%</td>
</tr>
<tr>
<th>MSN</th>
<td>5%</td>
<td>95%</td>
</tr>
<tr>
<th>ebay</th>
<td>5%</td>
<td>95%</td>
</tr>
<tr>
<th>Amazon</th>
<td>38%</td>
<td>62%</td>
</tr>
<tr>
<th>YouTube</th>
<td>9%</td>
<td>91%</td>
</tr>
<tr>
<th>CNN</th>
<td>15%</td>
<td>85%</td>
</tr>
</table>
<p class="gloss"><strong>Note: </strong> Times are for page loads with an empty cache over Comcast cable modem (~2.5 mbps).</p>
</div>
<h3 id="browsercache">Shouldn&#8217;t everything be saved in the browser&#8217;s cache anyway?</h3>
<p>The conclusion is the same: Reducing the number of HTTP requests has the biggest impact on reducing response time and is often the easiest performance improvement to make. In the next article we&#8217;ll look at the impact of caching, and some surprising real-world findings.</p>
<p class="disclaimer">Disclaimer: Design imperatives dictating visual richness need to be weighed against this request-reduction goal. When you need visual richness, additional steps can be taken &#8212; aggregating JS files, using CSS sprites, etc. &#8212; but visual richness does tend to run counter to a slender HTTP request pipeline.</p>
]]></content:encoded>
			<wfw:commentRss>http://yuiblog.com/blog/2006/11/28/performance-research-part-1/feed/</wfw:commentRss>
		</item>
	</channel>
</rss><!-- Dynamic Page Served (once) in 0.658 seconds --><!-- Cached page served by WP-Cache -->
