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

<channel>
	<title>phpied.com</title>
	<atom:link href="http://www.phpied.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.phpied.com</link>
	<description>Stoyan&#039;s blog</description>
	<lastBuildDate>Sun, 05 May 2013 19:47:31 +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>
		<item>
		<title>Here&#8217;s to a faster Recommendations plugin</title>
		<link>http://www.phpied.com/heres-to-a-faster-recommendations-plugin/</link>
		<comments>http://www.phpied.com/heres-to-a-faster-recommendations-plugin/#comments</comments>
		<pubDate>Sun, 05 May 2013 19:47:31 +0000</pubDate>
		<dc:creator>Stoyan</dc:creator>
				<category><![CDATA[facebook]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://www.phpied.com/?p=1705</guid>
		<description><![CDATA[So I've been part of the quest of making all Facebook social plugins faster, even if it means rewriting them from scratch. After the Send plugin, Like button (perf optimizations described here), Follow plugin, Facepile and Likebox (perf details here), now you have a faster Recommendations plugin. The techniques used to make it faster are [...]]]></description>
				<content:encoded><![CDATA[<p>So I've been part of the quest of making all Facebook social plugins faster, even if it means rewriting them from scratch. After the <a href="https://developers.facebook.com/docs/reference/plugins/send/">Send plugin</a>, <a href="https://developers.facebook.com/docs/reference/plugins/like/">Like</a> button (<a href="http://calendar.perfplanet.com/2012/liking-performance/">perf optimizations described here</a>), <a href="https://developers.facebook.com/docs/reference/plugins/follow">Follow</a> plugin, <a href="https://developers.facebook.com/docs/reference/plugins/facepile">Facepile</a> and <a href="https://developers.facebook.com/docs/reference/plugins/like-box/">Likebox</a> (<a href="https://www.facebook.com/notes/facebook-engineering/like-box-plugin-now-2-4x-faster/10151322164543920">perf details here</a>), now you have a faster <a href="https://developers.facebook.com/docs/reference/plugins/recommendations/">Recommendations</a> plugin.</p>
<p>The techniques used to make it faster are simple and effective: better resource packaging, reducing number of requests, inlining CSS, reducing the amount of CSS and JS by untangling dependencies, cleaning up, and sometimes simply rewriting. You can read more about these in the previous posts.</p>
<p>Now the results. The before-after comparison is accurate because it uses snapshots taken at the same time. This is possible because we kept an old endpoint serving the old code path. The official URL is <code>/plugins/recommendations.php</code> but we kept the legacy URL <code>/widgets/recommendations.php</code> pointing to the old code for a little while.</p>
<h4>Before</h4>
<ul>
<li>WPT: <a href="http://www.webpagetest.org/result/130320_JH_7BB/">http://www.webpagetest.org/result/130320_JH_7BB/</a></li>
<li>Render start: 0.854s</li>
<li>Fully loaded: 1.187s</li>
<li># of requests: 15</li>
<li>Total payload: 333 KB</li>
</ul>
<h4>After</h4>
<ul>
<li>WPT: <a href="http://www.webpagetest.org/result/130320_SJ_7B8/">http://www.webpagetest.org/result/130320_SJ_7B8/</a></li>
<li>Render start: 0.378s</li>
<li>Fully loaded: 0.569s</li>
<li># of requests: 10</li>
<li>Total payload: 48 KB</li>
</ul>
<h4>Some analysis</h4>
<p>The <em>total payload</em> change is drastic. Mainly due to better packaging. And better JS modules and dependencies.</p>
<p>The <em>number of requests</em> is reduced by 1/3. Not as drastic, but not too bad either. Most of the requests are images, which is ok. They don't block anything and whenever they arrive, they are welcome. But they are not on the critical path. The reduced requests are all JavaScript. We already had a previous optimization so CSS was already inlined. But thanks to rewrites, now the HTML payload (including inline CSS) is 6.2K gzipped, down from 9.4K. Which means the initial paint can start sooner.</p>
<p>The <em>initial paint</em> (render start) now happens in half the time. And, even better, the initial paint is a complete plugin, except for the images. While before it was just a partial content. This is because CSS is here early and all JS is out of the way (<a href="http://calendar.perfplanet.com/2011/the-art-and-craft-of-the-async-snippet/">async loaded</a>, also take a <a href="https://www.facebook.com/note.php?note_id=10151176218703920">peek here</a>)</p>
<p><img src="http://www.phpied.com/wp-content/uploads/2013/05/Pasted-Image-5513-1118-AM-2.png" alt="initial paint screenshots" /></p>
<p>The <em>fully loaded</em> time is not all that important since the user has a usable list of recommendations already delivered with the initial paint. But it's still 2x faster which makes me happy.</p>
<h3>All in all</h3>
<p>2x faster plugin overall, 2x faster (and infinitely better) first impression. 7x payload improvement.</p>
<h3>Making the web faster and other personal notes</h3>
<p>Just want to take a second to mention how good it feels to be working on such high-impact performance optimizations. These social plugins are everywhere on the web. By making them faster I am fortunate to have the opportunity to make the whole web faster. Meaning make millions of sites faster, affecting the live of billions of people, every day.</p>
<p>What can I say, Facebook is a great place to work. The people, the impact. Every line you write matters. It's also up to you to pick what do you want to work on and where your talents and interests will have the greatest impact. And then there are the hackathons and hackamonths which means even more freedom.</p>
<p>I recently finished a hackamonth project, which explains why I've been silent here and on Twitter and everywhere (yet, thanks to O'Reilly folks, even though I missed a few deadlines, we were able to <a href="http://www.amazon.com/dp/1449320198/?tag=w3clubs-20">push this baby out the door</a>). Let me tell you - a hack-a-month is better than vacation. Being left alone for a month to explore a completely new (to you) territory - priceless!</p>
<p>(Oh, if that sounds something you'd like to do, hit me up on ssttoo at ymail with your resume. FB now has engineering offices in NYC, Seattle and London, so if moving was a problem, now there are more options)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpied.com/heres-to-a-faster-recommendations-plugin/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>CSS animations off the UI thread</title>
		<link>http://www.phpied.com/css-animations-off-the-ui-thread/</link>
		<comments>http://www.phpied.com/css-animations-off-the-ui-thread/#comments</comments>
		<pubDate>Tue, 12 Mar 2013 05:25:28 +0000</pubDate>
		<dc:creator>Stoyan</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://www.phpied.com/?p=1700</guid>
		<description><![CDATA[This excellent Google I/O talk mentions that Chrome for Android moves the CSS animations off of the UI thread, which is, of course, a great idea. Playing around with it, here's what I found: Browser support: Desktop Safari, iOS Safari, Android Chrome. You need to use CSS transforms. Animating regular properties doesn't work. Update: (see [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.youtube.com/watch?v=hAzhayTnhEI">This excellent Google I/O talk</a> mentions that Chrome for Android moves the CSS animations off of the UI thread, which is, of course, a great idea. Playing around with it, here's what I found:</p>
<ul>
<li>Browser support: Desktop Safari, iOS Safari, Android Chrome. </li>
<li>You need to use CSS transforms. Animating regular properties doesn't work.</li>
</ul>
<p><strong>Update</strong>: (see comments) confirmed support in IE10. Reported support in Firefox OS too, but I cannot personally confirm</p>
<p>More details and test page below.</p>
<h2>Single UI thread</h2>
<p>As you probably know the browser is single threaded. Do something heavy in ECMAScript land and everything freezes.</p>
<h2>The big idea</h2>
<p>CSS animations should be excluded from the "everything" that freezes.</p>
<h2>Test page</h2>
<p><a href="http://www.phpied.com/files/css-thread/thread.html">Here's a test page</a> with some animations. Click the kill button and see what happens.</p>
<p><iframe src="http://www.phpied.com/files/css-thread/thread.html" width="600px" height="250px"></iframe></p>
<h2>Animations</h2>
<p>The red box that spins is animated like:</p>
<div class="hl-main">
<pre><span class="hl-identifier">.spin</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
  </span><span class="hl-reserved">animation:</span><span class="hl-code"> </span><span class="hl-number">3</span><span class="hl-code">s</span><span class="hl-code"> </span><span class="hl-code">rotate</span><span class="hl-code"> </span><span class="hl-code">linear</span><span class="hl-code"> </span><span class="hl-code">infinite</span><span class="hl-reserved"></span><span class="hl-code">;
</span><span class="hl-brackets">}</span><span class="hl-code">
 
</span><span class="hl-var">@keyframes</span><span class="hl-code"> </span><span class="hl-identifier">rotate</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
  </span><span class="hl-identifier">from</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-reserved">transform:</span><span class="hl-code"> </span><span class="hl-code">rotate</span><span class="hl-code">(</span><span class="hl-number">0</span><span class="hl-code">deg</span><span class="hl-code">)</span><span class="hl-reserved"></span><span class="hl-code">;</span><span class="hl-brackets">}</span><span class="hl-code">
  </span><span class="hl-identifier">to</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-reserved">transform:</span><span class="hl-code"> </span><span class="hl-code">rotate</span><span class="hl-code">(</span><span class="hl-number">360</span><span class="hl-code">deg</span><span class="hl-code">)</span><span class="hl-reserved"></span><span class="hl-code">;</span><span class="hl-brackets">}</span><span class="hl-code">
</span><span class="hl-brackets">}</span></pre>
</div>
<p>The green one is also animated with a transform:</p>
<div class="hl-main">
<pre><span class="hl-identifier">.walkabout-new-school</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
  </span><span class="hl-reserved">animation:</span><span class="hl-code"> </span><span class="hl-number">3</span><span class="hl-code">s</span><span class="hl-code"> </span><span class="hl-code">slide-transform</span><span class="hl-code"> </span><span class="hl-code">linear</span><span class="hl-code"> </span><span class="hl-code">infinite</span><span class="hl-reserved"></span><span class="hl-code">;
</span><span class="hl-brackets">}</span><span class="hl-code">
 
</span><span class="hl-var">@keyframes</span><span class="hl-code"> </span><span class="hl-identifier">slide-transform</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
  </span><span class="hl-identifier">from</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-reserved">transform:</span><span class="hl-code"> </span><span class="hl-code">translatex</span><span class="hl-code">(</span><span class="hl-number">0</span><span class="hl-code">)</span><span class="hl-reserved"></span><span class="hl-code">;</span><span class="hl-brackets">}</span><span class="hl-code">
  50% </span><span class="hl-brackets">{</span><span class="hl-reserved">transform:</span><span class="hl-code"> </span><span class="hl-code">translatex</span><span class="hl-code">(</span><span class="hl-number">300</span><span class="hl-string">px</span><span class="hl-code">)</span><span class="hl-reserved"></span><span class="hl-code">;</span><span class="hl-brackets">}</span><span class="hl-code">
  </span><span class="hl-identifier">to</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-reserved">transform:</span><span class="hl-code"> </span><span class="hl-code">translatex</span><span class="hl-code">(</span><span class="hl-number">0</span><span class="hl-code">)</span><span class="hl-reserved"></span><span class="hl-code">;</span><span class="hl-brackets">}</span><span class="hl-code">
</span><span class="hl-brackets">}</span></pre>
</div>
<p>The blue one is animated using the <code>margin-left</code> property, not a transform:</p>
<div class="hl-main">
<pre><span class="hl-identifier">.walkabout-old-school</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
  </span><span class="hl-reserved">animation:</span><span class="hl-code"> </span><span class="hl-number">3</span><span class="hl-code">s</span><span class="hl-code"> </span><span class="hl-code">slide-margin</span><span class="hl-code"> </span><span class="hl-code">linear</span><span class="hl-code"> </span><span class="hl-code">infinite</span><span class="hl-reserved"></span><span class="hl-code">;
</span><span class="hl-brackets">}</span><span class="hl-code">
 
</span><span class="hl-var">@keyframes</span><span class="hl-code"> </span><span class="hl-identifier">slide-margin</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
  </span><span class="hl-identifier">from</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-reserved">margin-left:</span><span class="hl-code"> </span><span class="hl-number">0</span><span class="hl-reserved"></span><span class="hl-code">;</span><span class="hl-brackets">}</span><span class="hl-code">
  50% </span><span class="hl-brackets">{</span><span class="hl-reserved">margin-left:</span><span class="hl-code"> </span><span class="hl-number">100</span><span class="hl-string">%</span><span class="hl-reserved"></span><span class="hl-code">;</span><span class="hl-brackets">}</span><span class="hl-code">
  </span><span class="hl-identifier">to</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-reserved">margin-left:</span><span class="hl-code"> </span><span class="hl-number">0</span><span class="hl-reserved"></span><span class="hl-code">;</span><span class="hl-brackets">}</span><span class="hl-code">
</span><span class="hl-brackets">}</span></pre>
</div>
<h2>Kill switch</h2>
<p>The kill button just pegs the CPU in a infinite loop for 2 seconds:</p>
<div class="hl-main">
<pre><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">kill</span><span class="hl-brackets">(</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
  </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">start</span><span class="hl-code"> = +</span><span class="hl-reserved">new</span><span class="hl-code"> </span><span class="hl-builtin">Date</span><span class="hl-code">;
  </span><span class="hl-reserved">while</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-code">+</span><span class="hl-reserved">new</span><span class="hl-code"> </span><span class="hl-builtin">Date</span><span class="hl-code"> - </span><span class="hl-identifier">start</span><span class="hl-code"> &lt; </span><span class="hl-number">2000</span><span class="hl-brackets">)</span><span class="hl-brackets">{</span><span class="hl-brackets">}</span><span class="hl-code">
</span><span class="hl-brackets">}</span></pre>
</div>
<h2>Results</h2>
<p>In non-supporting browsers, which is most of them, the kill switch kills all the animations. Business as usual.</p>
<p>In the supporting browsers (All Safaris and Andriod Chrome) the kill only affects the blue button, the one that animates a CSS property, as opposed to using a CSS transform. But the animations that use a transform keep on going!</p>
<h2>Take aways</h2>
<ol>
<li>Rejoice! The future is here! Drink and dance uncontrollably around the campfire!</li>
<li>After you sober up, make sure your CSS animations <a href="https://developer.mozilla.org/en-US/docs/CSS/transform">use <code>transform:</code></a> where possible</li>
<li>Keep migrating them JS animations to CSS</li>
<li>Bug your browser vendor to support this</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.phpied.com/css-animations-off-the-ui-thread/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>C3PO: Common 3rd-party objects</title>
		<link>http://www.phpied.com/c3po-common-3rd-party-objects/</link>
		<comments>http://www.phpied.com/c3po-common-3rd-party-objects/#comments</comments>
		<pubDate>Mon, 18 Feb 2013 21:29:39 +0000</pubDate>
		<dc:creator>Stoyan</dc:creator>
				<category><![CDATA[facebook]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://www.phpied.com/?p=1696</guid>
		<description><![CDATA[Problem: too much JavaScript in your page to handle 3rd party widgets (e.g. Like buttons) Possible solution: a common piece of JavaScript to handle all third parties' needs What JavaScript? If you've read the previous post, you see that the most features in a third party widget are possible only if you inject JavaScript from [...]]]></description>
				<content:encoded><![CDATA[<p><strong>Problem</strong>: too much JavaScript in your page to handle 3rd party widgets (e.g. Like buttons)<br />
<strong>Possible solution</strong>: a common piece of JavaScript to handle all third parties' needs</p>
<p><img src="http://www.phpied.com/wp-content/uploads/2013/02/3t1jsi.jpg" alt="3t1jsi" width="334" height="302" class="aligncenter size-full wp-image-1697" /></p>
<h2>What JavaScript?</h2>
<p>If you've read <a href="http://www.phpied.com/speed-geeks-guide-to-facebook-buttons/">the previous post</a>, you see that the most features in a third party widget are possible only if you inject JavaScript from the third party provider into your page. Having "a secret agent" on your page, the provider can take care of problems such as appropriately resizing the widget.</p>
<h2>Why is this a problem?</h2>
<p>Third party scripts can be a SPOF (an outage), unless you load them asynchronously. They can block <code>onload</code>, unless the provider lets you load it in an iframe (and most don't). There can be security implications because you're hosting the script in your page with all permissions associated with that. And in any case, it's just too much JavaScript for the browser to parse and execute (think of mobile devices)</p>
<p>If you include the most common Like, Tweet and +1 buttons and throw in Disqus comments, you're looking at well over 100K (minified, gzipped) worth of JavaScript (<a href="http://www.webpagetest.org/result/130218_5G_QJM/">wpt</a> for <a href="http://jsbin.com/iketes/1/edit">this jsbin</a>)</p>
<p>This is more than the whole of jQuery, which <a href="http://calendar.perfplanet.com/2011/lazy-evaluation-of-commonjs-modules/">previous</a> <a href="http://jsperf.com/zepto-jq-eval">experiments</a> show can take the noticeable 200ms just to parse and evaluate (assuming it's cached) on an iPhone or Android.</p>
<h2>What does all of this JS do?</h2>
<p>The JavaScript used by third parties is not always all about social widgets. The JS also provides API call utilities, other dialogs and so on. But the tasks related to social widgets are:</p>
<ol>
<li>Find html tags that say "there be widget here!" and insert an iframe at that location, pointing to a URL hosted by the third party</li>
<li>Listen to requests from the new iframes fulfill these requests. The most common request is "resize me, please"</li>
</ol>
<p>Now, creating an iframe and resizing it doesn't sound like much, right? But every provider has to do it over and over again. It's just a wasted code duplication that the browser has to deal with.</p>
<p>Can't we just not duplicate this JavaScript? Can we have a common library that can take care of all widgets there are?</p>
<h2>C3PO draft</h2>
<p><a href="http://www.phpied.com/files/c3po/c3po.html">Here's a demo page</a> of what I have in mind. The page is loading third party widgets: like, tweet, +1 and another one I created just for illustration of the messaging part.</p>
<p>It has a possible solution I drafted as the <code>c3po</code> object. View source, the JS is inline.</p>
<p>What does c3po do?</p>
<p>The idea is that the developer should not have to make any changes to existing sites, other than remove FB, G, Tw, etc JS files and replace with the single c3po library. In other words, only the JS loading part should be changed, not the individual widgets code.</p>
<p>c3po is a small utility which can be packaged together with the rest of your application code, so there will be no additional HTTP requests.</p>
<h2>Parsing and inserting iframes</h2>
<p>The first task for c3po is to insert iframes. It looks for HTML tags such as</p>
<div class="hl-main">
<pre><span class="hl-code">&lt;</span><span class="hl-identifier">div</span><span class="hl-code"> </span><span class="hl-reserved">class</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">fb-like</span><span class="hl-quotes">&quot;</span><span class="hl-code"> </span><span class="hl-identifier">data</span><span class="hl-code">-</span><span class="hl-identifier">href</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">http://phpied.com</span><span class="hl-quotes">&quot;</span><span class="hl-code">&gt;&lt;/</span><span class="hl-identifier">div</span><span class="hl-code">&gt;</span></pre>
</div>
<p>Similar tags are generated by each provider's "wizard" configuration tools.</p>
<p>In place of this tag, there should be an iframe, so the result (generated html) after c3po's parsing should roughly be like:</p>
<div class="hl-main">
<pre><span class="hl-code">&lt;</span><span class="hl-identifier">div</span><span class="hl-code"> </span><span class="hl-reserved">class</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">fb-like</span><span class="hl-quotes">&quot;</span><span class="hl-code"> </span><span class="hl-identifier">data</span><span class="hl-code">-</span><span class="hl-identifier">href</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">http://phpied.com</span><span class="hl-quotes">&quot;</span><span class="hl-code">&gt;
  &lt;</span><span class="hl-identifier">iframe</span><span class="hl-code"> 
    </span><span class="hl-identifier">src</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">http://facebook.com/plugins/like.php?href=http://phpied.com</span><span class="hl-quotes">&quot;</span><span class="hl-code">&gt;
  &lt;/</span><span class="hl-identifier">iframe</span><span class="hl-code">&gt;
&lt;/</span><span class="hl-identifier">div</span><span class="hl-code">&gt;</span></pre>
</div>
<p>The way to do this across providers is to just have every <code>data-</code> attribute passed as a parameter to the 3rd party URL.</p>
<p>Third parties can be setup using a <code>register()</code> method:</p>
<div class="hl-main">
<pre><span class="hl-comment">//</span><span class="hl-comment"> FB</span><span class="hl-comment"></span><span class="hl-code">
</span><span class="hl-identifier">c3po</span><span class="hl-code">.</span><span class="hl-identifier">register</span><span class="hl-brackets">(</span><span class="hl-brackets">{</span><span class="hl-code">
  </span><span class="hl-quotes">'</span><span class="hl-string">fb-like</span><span class="hl-quotes">'</span><span class="hl-code">: 
    </span><span class="hl-quotes">'</span><span class="hl-string">https://www.facebook.com/plugins/like.php?</span><span class="hl-quotes">'</span><span class="hl-code">,
  </span><span class="hl-quotes">'</span><span class="hl-string">fb-send</span><span class="hl-quotes">'</span><span class="hl-code">:
    </span><span class="hl-quotes">'</span><span class="hl-string">https://www.facebook.com/plugins/send.php?</span><span class="hl-quotes">'</span><span class="hl-code">,
</span><span class="hl-brackets">}</span><span class="hl-brackets">)</span><span class="hl-code">;
 
</span><span class="hl-comment">//</span><span class="hl-comment"> Tw</span><span class="hl-comment"></span><span class="hl-code">
</span><span class="hl-identifier">c3po</span><span class="hl-code">.</span><span class="hl-identifier">register</span><span class="hl-brackets">(</span><span class="hl-brackets">{</span><span class="hl-code">
  </span><span class="hl-quotes">'</span><span class="hl-string">twitter-share-button</span><span class="hl-quotes">'</span><span class="hl-code">:
    </span><span class="hl-quotes">'</span><span class="hl-string">https://platform.twitter.com/widgets/tweet_button.html#</span><span class="hl-quotes">'</span><span class="hl-code">
</span><span class="hl-brackets">}</span><span class="hl-brackets">)</span><span class="hl-code">;
 
</span><span class="hl-comment">//</span><span class="hl-comment"> ...</span><span class="hl-comment"></span></pre>
</div>
<p>The only additional parameter passed to the third party URL is <code>cpo-guid=...</code>, a unique ID so that the iframe can identify itself when requesting services.</p>
<p>The parsing and inserting frames works today, as the demo shows. The only problem is you don't know how big the iframes should be. You can guess, but you'll be wrong, given i18n labels and different layouts for the widgets. It's best if the widget tells you (tells c3po) how big it should be by sending a message to it.</p>
<h2>X-domain messaging</h2>
<p>What we need here is the iframe hosted on the provider's domain to communicate with the page (and c3po script) hosted on your page. <a href="http://msdn.microsoft.com/en-us/magazine/ff800814.aspx">X-domain messaging is hard</a>, it requires different methods for browsers and I'm not even going to pretend I know how it works. But, if the browser supports <code>postMessage</code>, it becomes pretty easy. At the time of writing <a href="http://caniuse.com/#feat=x-doc-messaging">94.42% of the browsers</a> support it. Should we let the other 5% drag us down? I'd say No!</p>
<p>c3po is meant to only work in the browsers that support postMessage, which means for IE7 and below, the implementers can resort to the old way of including all providers' JS. Or just have less-than-ideally-resized widgets with reasonable defaults.</p>
<p>When the widget wants something, it should send a message, e.g.</p>
<div class="hl-main">
<pre><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">msg</span><span class="hl-code"> = </span><span class="hl-identifier">JSON</span><span class="hl-code">.</span><span class="hl-identifier">stringify</span><span class="hl-brackets">(</span><span class="hl-brackets">{</span><span class="hl-code">
  </span><span class="hl-identifier">type</span><span class="hl-code">: </span><span class="hl-quotes">'</span><span class="hl-string">resize</span><span class="hl-quotes">'</span><span class="hl-code">,
  </span><span class="hl-identifier">guid</span><span class="hl-code">: </span><span class="hl-quotes">'</span><span class="hl-string">2c23263549d648000</span><span class="hl-quotes">'</span><span class="hl-code">,
  </span><span class="hl-identifier">width</span><span class="hl-code">: </span><span class="hl-number">200</span><span class="hl-code">, 
  </span><span class="hl-identifier">height</span><span class="hl-code">: </span><span class="hl-number">300</span><span class="hl-code">
</span><span class="hl-brackets">}</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-identifier">parent</span><span class="hl-code"> &amp;&amp; </span><span class="hl-identifier">parent</span><span class="hl-code">.</span><span class="hl-identifier">postMessage</span><span class="hl-brackets">(</span><span class="hl-identifier">msg</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">*</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;</span></pre>
</div>
<p>See <a href="http://tools.w3clubs.com/pagr/plugin.php?height=70&#038;width=90&#038;type=jpg&#038;c3po-guid=2c23263549d648000">the example widget</a> for some working code.</p>
<p>The c3po code that handles the message will check the GUID and the origin of the message and if all checks out it will do something with the iframe, e.g. resize it.</p>
<p>Again, <a href="http://www.phpied.com/files/c3po/c3po.html">take a look at the demo code</a> to see how it all clicks together</p>
<h2>Next?</h2>
<p>As you see in the demo, only the example widget is resized properly. This is because it's the only one that sends messages that make sense to c3po.</p>
<p>Next step will be to have all widget providers agree on the messages and we're good to go! The ultimate benefit: one JS for all your widget-y needs. One JS you can package with your own code and have virtually 0 cost during initial load. And when you're ready: <code>c3po.parse()</code> and voila! - widgets appear. </p>
<p>Of course, this is just a draft for c3po, I'm surely missing a lot of things, but the idea is to have soemthing to start the dialogue and have this developed in the open. Here's <a href="https://github.com/stoyan/c3po">the github repo for your forking pleasure</a>.</p>
<p>Make sense? Let's talk.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpied.com/c3po-common-3rd-party-objects/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Speed geek&#8217;s guide to Facebook buttons</title>
		<link>http://www.phpied.com/speed-geeks-guide-to-facebook-buttons/</link>
		<comments>http://www.phpied.com/speed-geeks-guide-to-facebook-buttons/#comments</comments>
		<pubDate>Thu, 14 Feb 2013 22:15:01 +0000</pubDate>
		<dc:creator>Stoyan</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://www.phpied.com/?p=1690</guid>
		<description><![CDATA[or "How to help your users share your content on Facebook and not hurt performance" Facebook's like button is much much faster now than it used to be. It also uses much fewer resources. And lazy-evaluates JavaScript on demand. And so on. But it's still not the only option when it comes to putting a [...]]]></description>
				<content:encoded><![CDATA[<p>or "How to help your users share your content on Facebook and not hurt performance"</p>
<p>Facebook's like button is <a href="http://calendar.perfplanet.com/2012/liking-performance/">much much faster now</a> than it used to be. It also uses much fewer resources. And lazy-evaluates JavaScript on demand. And so on. But it's still not the only option when it comes to putting a "share this article on Facebook" widgety thing on your site.</p>
<p>The list of options is roughly listed in order of faster (and least features) to slowest (and most features).</p>
<h2>#1: A share link</h2>
<p>Note that this feature has been deprecated but it still does work. And you see it all over the place.</p>
<p>A simple link to <code>sharer.php</code> endpoint is all it takes. The <code>u</code> parameter is your URL. E.g.:</p>
<div class="hl-main">
<pre><span class="hl-brackets">&lt;</span><span class="hl-reserved">a</span><span class="hl-code"> 
  </span><span class="hl-var">href</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">https://www.facebook.com/sharer/sharer.php?u=phpied.com</span><span class="hl-quotes">&quot;</span><span class="hl-code"> 
  </span><span class="hl-var">target</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">_blank</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">&gt;</span><span class="hl-code">
  Share on Facebook
</span><span class="hl-brackets">&lt;/</span><span class="hl-reserved">a</span><span class="hl-brackets">&gt;</span></pre>
</div>
<div class="alt">
<h4>Try it:</h4>
<p><a href="https://www.facebook.com/sharer/sharer.php?u=phpied.com" target="_blank">Share on Facebook</a>
</div>
<p>The above is a hardcoded URL. You can, of course, spit the current URL on the server side. A JS-only client-side solution could be to take the <code>document.location</code>. You can also pop a window. And use a button, or an image. Say something like:</p>
<div class="hl-main">
<pre><span class="hl-brackets">&lt;</span><span class="hl-reserved">button</span><span class="hl-code"> </span><span class="hl-var">id</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">sharer</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">&gt;</span><span class="hl-code">Share</span><span class="hl-brackets">&lt;/</span><span class="hl-reserved">button</span><span class="hl-brackets">&gt;</span><span class="hl-code">
</span><span class="hl-brackets">&lt;</span><span class="hl-reserved">script</span><span class="hl-brackets">&gt;</span>
<span class="hl-builtin">document</span><span class="hl-code">.</span><span class="hl-identifier">getElementById</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">sharer</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">.</span><span class="hl-identifier">onclick</span><span class="hl-code"> = </span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
  </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">url</span><span class="hl-code"> = </span><span class="hl-quotes">'</span><span class="hl-string">https://www.facebook.com/sharer/sharer.php?u=</span><span class="hl-quotes">'</span><span class="hl-code">;
  </span><span class="hl-identifier">url</span><span class="hl-code"> += </span><span class="hl-identifier">encodeURIComponent</span><span class="hl-brackets">(</span><span class="hl-identifier">location</span><span class="hl-code">.</span><span class="hl-identifier">href</span><span class="hl-brackets">)</span><span class="hl-code">;
  </span><span class="hl-builtin">window</span><span class="hl-code">.</span><span class="hl-identifier">open</span><span class="hl-brackets">(</span><span class="hl-identifier">url</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">fbshare</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">width=640,height=320</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-brackets">}</span><span class="hl-code">;</span>
<span class="hl-brackets">&lt;/</span><span class="hl-reserved">script</span><span class="hl-brackets">&gt;</span></pre>
</div>
<div class="alt">
<h4>Try it:</h4>
<p><button id="sharer">Share</button><br />
<script>
document.getElementById('sharer').onclick = function () {
  var url = 'https://www.facebook.com/sharer/sharer.php?u=';
  url += encodeURIComponent(location.href);
  window.open(url, 'fbshare', 'width=640,height=320');
};
</script>
</div>
<h3>Method #1's performance price: none</h3>
<p>This is just a link you host in your HTML or bit of JavaScript you can inline or package with your own JavaScript (it is, after all, your own JavaScript)</p>
<h2>#2: Feed dialog</h2>
<p>The feed dialog a next incarnation of the share popup. </p>
<p>It can also be as simple as a link, like so</p>
<pre>https://www.facebook.com/dialog/feed
  ?link=jspatterns.com
  &#038;app_id=179150165472010
  &#038;redirect_uri=http://phpied.com</pre>
<div class="alt">
<h4>Try it:</h4>
<p><a href="https://www.facebook.com/dialog/feed?link=jspatterns.com&#038;app_id=179150165472010&#038;redirect_uri=http://phpied.com">Share</a>
</div>
<p>You need a <code>redirect_uri</code> which can be something like a thank you page. But instead of "thank you", you can simply go back to the article by making <code>redirect_uri</code> and <code>link</code> point to the same URL</p>
<p>Again, a client-only solution could be something like:</p>
<div class="hl-main">
<pre><span class="hl-code">  </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">feed</span><span class="hl-code"> = </span><span class="hl-quotes">'</span><span class="hl-string">https://www.facebook.com/dialog/feed?app_id=179150165472010</span><span class="hl-quotes">'</span><span class="hl-code">;
  </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">url</span><span class="hl-code"> = </span><span class="hl-identifier">encodeURIComponent</span><span class="hl-brackets">(</span><span class="hl-identifier">location</span><span class="hl-code">.</span><span class="hl-identifier">href</span><span class="hl-brackets">)</span><span class="hl-code">;
  </span><span class="hl-identifier">feed</span><span class="hl-code"> += </span><span class="hl-quotes">'</span><span class="hl-string">&amp;link=</span><span class="hl-quotes">'</span><span class="hl-code"> + </span><span class="hl-identifier">url</span><span class="hl-code"> + </span><span class="hl-quotes">'</span><span class="hl-string">&amp;redirect_uri=</span><span class="hl-quotes">'</span><span class="hl-code"> + </span><span class="hl-identifier">url</span><span class="hl-code">;
  </span><span class="hl-builtin">window</span><span class="hl-code">.</span><span class="hl-identifier">open</span><span class="hl-brackets">(</span><span class="hl-identifier">feed</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">fbshare</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">width=640,height=480</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;</span></pre>
</div>
<p>The result is a dialog that looks like:</p>
<p><img src="http://www.phpied.com/wp-content/uploads/2013/02/feed.jpg" alt="feed" width="599" height="355" class="aligncenter size-full wp-image-1691" /></p>
<p>But this feed dialog can also be a popup. You do this by adding <code><strong>&#038;display=popup</strong></code>. This hides the FB chrome. And you can also make the "thank you" page just a simple page that closes the window.</p>
<div class="alt">
<h4>Try it:</h4>
<p><button onclick="window.open('https://www.facebook.com/dialog/feed?link=jspatterns.com&#038;app_id=179150165472010&#038;redirect_uri=http://phpied.com/files/fb/window.close.html&#038;display=popup', 'fbshare', 'width=640,height=320');">Feed dialog popup</button>
</div>
<p>The result:</p>
<p><img src="http://www.phpied.com/wp-content/uploads/2013/02/feedpopup.jpg" alt="feedpopup" width="615" height="388" class="aligncenter size-full wp-image-1694" /></p>
<p>The other required thing is the <strong>app id</strong>. You need one. But that's actually cool because it has side benefits. For example better error messages for you (the app admin) that the users don't see. It also gives you a little "via phpied.com" attribution linked to the App URI which is a nice traffic boost hopefully as your sharer's friends see the story in their newsfeed or timeline and click the "via".</p>
<p><img src="http://www.phpied.com/wp-content/uploads/2013/02/story.jpg" alt="story" width="422" height="248" class="aligncenter size-full wp-image-1692" /></p>
<p>So, App ID is good, you can <a href="https://developers.facebook.com/apps/">get one here</a>.</p>
<p>Additionally there's a bunch of other params you can pass to the feed dialog to control how the story is displayed. You can provide title, description, image, etc. <a href="https://developers.facebook.com/docs/reference/dialogs/feed/">Full list here.</a></p>
<h3>Method #2's performance price: none</h3>
<p>Feed dialog has the same (non-existing) performance requirements as the share links. It's all inline. Any content coming from Facebook is only on user interaction.</p>
<p>BTW, this is the method youtube currently uses.</p>
<h2>#3: Feed dialog via JS SDK</h2>
<p>Now we move on from simple links and popups to using the JavaScript SDK.</p>
<p><strong>First things first, you absolutely <a href="http://calendar.perfplanet.com/2011/the-art-and-craft-of-the-async-snippet/">must load the SDK asynchronously</a>. Or <a href="https://www.facebook.com/note.php?note_id=10151176218703920">non-onload-blocking-asynchronously in an iframe</a></strong>. More on these two later.</p>
<p>After you load the SDK like so:</p>
<div class="hl-main">
<pre><span class="hl-brackets">(</span><span class="hl-reserved">function</span><span class="hl-brackets">(</span><span class="hl-identifier">d</span><span class="hl-code">, </span><span class="hl-identifier">s</span><span class="hl-code">, </span><span class="hl-identifier">id</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
  </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">js</span><span class="hl-code">, </span><span class="hl-identifier">fjs</span><span class="hl-code"> = </span><span class="hl-identifier">d</span><span class="hl-code">.</span><span class="hl-identifier">getElementsByTagName</span><span class="hl-brackets">(</span><span class="hl-identifier">s</span><span class="hl-brackets">)</span><span class="hl-brackets">[</span><span class="hl-number">0</span><span class="hl-brackets">]</span><span class="hl-code">;
  </span><span class="hl-reserved">if</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-identifier">d</span><span class="hl-code">.</span><span class="hl-identifier">getElementById</span><span class="hl-brackets">(</span><span class="hl-identifier">id</span><span class="hl-brackets">)</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-reserved">return</span><span class="hl-code">;
  </span><span class="hl-identifier">js</span><span class="hl-code"> = </span><span class="hl-identifier">d</span><span class="hl-code">.</span><span class="hl-identifier">createElement</span><span class="hl-brackets">(</span><span class="hl-identifier">s</span><span class="hl-brackets">)</span><span class="hl-code">; </span><span class="hl-identifier">js</span><span class="hl-code">.</span><span class="hl-identifier">id</span><span class="hl-code"> = </span><span class="hl-identifier">id</span><span class="hl-code">;
  </span><span class="hl-identifier">js</span><span class="hl-code">.</span><span class="hl-identifier">src</span><span class="hl-code"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">//connect.facebook.net/en_US/all.js</span><span class="hl-quotes">&quot;</span><span class="hl-code">;
  </span><span class="hl-identifier">fjs</span><span class="hl-code">.</span><span class="hl-identifier">parentNode</span><span class="hl-code">.</span><span class="hl-identifier">insertBefore</span><span class="hl-brackets">(</span><span class="hl-identifier">js</span><span class="hl-code">, </span><span class="hl-identifier">fjs</span><span class="hl-brackets">)</span><span class="hl-code">;
</span><span class="hl-brackets">}</span><span class="hl-brackets">(</span><span class="hl-builtin">document</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">script</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">facebook-jssdk</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-brackets">)</span><span class="hl-code">;</span></pre>
</div>
<p>Then, whenever you're ready, you can make a call to get the feed dialog:</p>
<div class="hl-main">
<pre><span class="hl-identifier">FB</span><span class="hl-code">.</span><span class="hl-identifier">ui</span><span class="hl-brackets">(</span><span class="hl-brackets">{</span><span class="hl-code">
  </span><span class="hl-identifier">method</span><span class="hl-code">: </span><span class="hl-quotes">'</span><span class="hl-string">feed</span><span class="hl-quotes">'</span><span class="hl-code">,
  </span><span class="hl-identifier">redirect_uri</span><span class="hl-code">: </span><span class="hl-quotes">'</span><span class="hl-string">http://phpied.com/files/fb/window.close.html</span><span class="hl-quotes">'</span><span class="hl-code">,
  </span><span class="hl-identifier">link</span><span class="hl-code">: </span><span class="hl-quotes">'</span><span class="hl-string">http://phpied.com</span><span class="hl-quotes">'</span><span class="hl-code">,
  </span><span class="hl-comment">//</span><span class="hl-comment"> picture: '</span><span class="hl-url">http...jpg</span><span class="hl-comment">',</span><span class="hl-comment"></span><span class="hl-code">
  </span><span class="hl-identifier">caption</span><span class="hl-code">: </span><span class="hl-quotes">'</span><span class="hl-string">Awesomesauce</span><span class="hl-quotes">'</span><span class="hl-code">,
  </span><span class="hl-comment">//</span><span class="hl-comment"> description: 'Must read daily!'</span><span class="hl-comment"></span><span class="hl-code">
</span><span class="hl-brackets">}</span><span class="hl-brackets">)</span><span class="hl-code">;</span></pre>
</div>
<p>For a working example, check <a href="http://jsbin.com/utowek/2/edit">this example in jsbin</a></p>
<p>The result:</p>
<p><img src="http://www.phpied.com/wp-content/uploads/2013/02/jsbin-feed.jpg" alt="jsbin-feed" width="700" height="648" class="aligncenter size-full wp-image-1693" /></p>
<p>As you can see, this is now a real properly resized popup. No FB chrome, nice and clean. In general the JS SDK makes everything better. But you need to load it first - the performance price you pay for all the magic. </p>
<h3>Method #3's performance price: an async JS</h3>
<p>Opening the feed dialog this way requires you to load the Facebook JavaScript SDK. It's one JS file with a short expiration time (20 mins). When it loads, it also makes two additional requests required for cross-domain communication. These requests are small though and with long-expiration caching headers. Since the JS SDK is loaded many times during regular user's surfing throughout the web, these two additional requests have a very high probability of being cached. So is the JSSDK itself. If not cached, at least it's a conditional requests with likely a <code>304 Not Modified</code> response.</p>
<p><a href="http://www.webpagetest.org/result/130213_DR_929/1/details/">Here's the waterfall</a> of loading the <a href="http://jsbin.com/utowek/2/edit">jsbin test page</a> where you can see the JS SDK loading (all.js) and the two x-domain thingies (xd_arbiter.php)</p>
<p>Note that by default the JS SDK sends an additional request checking whether the user is logged in. If you don't need that, make sure you set the login <code>status</code> init property to <code>false</code>, as shown in the test page, like:</p>
<pre>FB.init({appId: 179150165472010, <strong>status: false</strong>});</pre>
<p>When loading the JS SDK you must absolutely make sure it's <a href="http://calendar.perfplanet.com/2011/the-art-and-craft-of-the-async-snippet/">loaded asynchronously</a>, and even better - <a href="https://www.facebook.com/note.php?note_id=10151176218703920">in an iframe</a>, so the <code>onload</code> of your page is never blocked.</p>
<h2>#4: Like button in an iframe</h2>
<p>We're coming to <a href="https://developers.facebook.com/docs/reference/plugins/like/">the Like button</a>. There are two ways to load it: either you create an iframe and point it to <code>/plugins/like.php</code> or you include the JS SDK and let the SDK create the iframe. Let's take a look at the you-create-iframe option first.</p>
<p>The integration is straightforward: You go to the help page, use the "wizard" configurator found there and end up with something like:</p>
<div class="hl-main">
<pre><span class="hl-brackets">&lt;</span><span class="hl-reserved">iframe</span><span class="hl-code"> 
  </span><span class="hl-var">src</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">//www.facebook.com/plugins/like.php?href=phpied.com</span><span class="hl-special">&amp;amp;</span><span class="hl-string">width=450</span><span class="hl-special">&amp;amp;</span><span class="hl-string">show_faces=true</span><span class="hl-special">&amp;amp;</span><span class="hl-string">height=80</span><span class="hl-quotes">&quot;</span><span class="hl-code"> 
  </span><span class="hl-var">scrolling</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">no</span><span class="hl-quotes">&quot;</span><span class="hl-code"> 
  </span><span class="hl-var">frameborder</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">0</span><span class="hl-quotes">&quot;</span><span class="hl-code"> 
  </span><span class="hl-var">style</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">border:none; overflow:hidden; width:450px; height:80px;</span><span class="hl-quotes">&quot;</span><span class="hl-code"> 
  </span><span class="hl-var">allowTransparency</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">true</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">&gt;</span><span class="hl-brackets">&lt;/</span><span class="hl-reserved">iframe</span><span class="hl-brackets">&gt;</span></pre>
</div>
<p>You're done!</p>
<p>The button comes in three layouts: standard (biggest), box_count and button_count</p>
<div class="alt">
<h4>Try it:</h4>
<p><strong>Standard</strong><br />
<iframe src="//www.facebook.com/plugins/like.php?href=phpied.com&amp;width=450&amp;show_faces=true&amp;height=80" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:80px;" allowTransparency="true"></iframe></p>
<p><strong>Box count</strong><br />
<iframe src="//www.facebook.com/plugins/like.php?href=phpied.com&amp;width=450&amp;height=80&amp;layout=box_count" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:80px;" allowTransparency="true"></iframe></p>
<p><strong>Button count</strong><br />
<iframe src="//www.facebook.com/plugins/like.php?href=phpied.com&amp;width=450&amp;height=40&amp;layout=button_count" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:40px;" allowTransparency="true"></iframe>
</div>
<p>As you can see, you get quite a bit more features here, e.g. number of likes and social context (who else has liked) in the standard layout. Also in the standard layout you get a little comment input. You don't get one in the other layouts because there's no space in the little iframe. You define the iframe and the code inside the iframe cannot break out of it and do something wild (or useful), e.g. open a big commenting dialog. Or make the iframe bigger because the word "Like" may be significantly longer in some languages. When you "trap" the iframe in your dimensions, it stays there.</p>
<h3>Method #4's performance price: iframe content</h3>
<p>In this method every time someone loads your page, they also visit a page (like.php) hosted by facebook.com. Now, <a href="http://calendar.perfplanet.com/2012/liking-performance/">this page is highly optimized</a>: it only has html, sprite and async lazy-executed JS (which doesn't block <code>onload</code>). 3 requests in total. Maybe some faces (profile photos), depending on the layout and whether the user's friends have liked the URL.</p>
<p>As you probably know, every iframe's <code>onload</code> blocks the parent window's <code>onload</code>. So, if you feel so inclined you can always do any old lazy-load trick in the book. E.g. create the iframe after <code>window.onload</code>, or "double-frame" it, or (for the webkits out there) write the iframe <code>src</code> with a <code>setTimeout</code> of 0.</p>
<p>Another thing to consider is to always load the iframe via https, so there's no http-https redirect if the user has opted to always use facebook via https.</p>
<h2>#5: Like button via SDK</h2>
<p>This is building on what you already know about #3 and #4: You load the SDK. You sprinkle &lt;fb:like&gt; (or &lt;div class="fb-like"&gt;) where you want buttons to appear. The SDK finds these and replaces them with iframes.</p>
<div class="hl-main">
<pre><span class="hl-comment">&lt;!--</span><span class="hl-comment"> all defaults </span><span class="hl-comment">--&gt;</span><span class="hl-code">
</span><span class="hl-brackets">&lt;</span><span class="hl-reserved">fb:like</span><span class="hl-brackets">&gt;</span><span class="hl-brackets">&lt;/</span><span class="hl-reserved">fb:like</span><span class="hl-brackets">&gt;</span><span class="hl-code">
 
</span><span class="hl-comment">&lt;!--</span><span class="hl-comment"> layout, send button </span><span class="hl-comment">--&gt;</span><span class="hl-code">
</span><span class="hl-brackets">&lt;</span><span class="hl-reserved">div</span><span class="hl-code"> </span><span class="hl-var">class</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">fb-like</span><span class="hl-quotes">&quot;</span><span class="hl-code"> </span><span class="hl-var">data-send</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">true</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">&gt;</span><span class="hl-brackets">&lt;/</span><span class="hl-reserved">div</span><span class="hl-brackets">&gt;</span></pre>
</div>
<p>If you don't need to specify the URL to like, it's the current page.</p>
<div id="fb-root"></div>
<p><script>(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script></p>
<div class="alt">
<h4>Try it:</h4>
<p><strong>Standard</strong><br />
<fb:like></fb:like></p>
<p><strong>box count</strong><br />
<fb:like layout="box_count"></fb:like></p>
<p><strong>button count</strong><br />
<fb:like layout="button_count"></fb:like>
</div>
<p>This is the most full-featured button implementation. It will resize the button as required by content and i18n. It will always present a comment dialog. (When people share with their own comment, these stories do better, because it's always nice to see a friend's comment attached to a URL, right?)</p>
<p>The good thing about this method is that you can load any other FB plugin (e.g. <a href="https://developers.facebook.com/docs/reference/plugins/follow/">follow button</a> by just adding an <code>fb:follow</code> in the HTML) without re-loading the SDK, it's already there and can handle all the plugins, dialogs and API requests.</p>
<h3>Method #5's performance price: JSSDK + iframe content</h3>
<p>Combining the features of methods #3 and #4 also combines their perfromance impact. Again, the like.php iframe is <a href="http://calendar.perfplanet.com/2012/liking-performance/">heavily optimized</a> and tiny. Also the SDK has a chance of being cached from the users visit on another page. And, of course, you always load the SDK asynchronously so it's impact on your initial page loading is minimal. Or load the SDK in an iframe so the impact is virtually 0.</p>
<p>So the total cost in terms of number of requests in empty cache view is 6. 3 from the iframe + 3 from the SDK. Full cache view should be 1 request - just the like.php frame with the current count, faces and so on.</p>
<p>But again, to minimize the impact, you just load the SDK in an iframe (so the whole widget doesn't block onload and doesn't SPOF) or asynchronously (so it doesn't SPOF and doesn't block onload in IEs) </p>
<h2>Summary</h2>
<style>td {border-bottom:1px solid #93BB3A;} td.fontname {text-align:left;} th {padding:5px;background:#C1E56D;}</style>
<table cellpadding="5">
<tr>
<th>#</th>
<th>Method</th>
<th>Features</th>
<th>Cost</th>
</tr>
<tr>
<td>1</td>
<td>Share link</td>
<td>link opens popup, no like count, no social context</td>
<td>none</td>
</tr>
<tr>
<td>2</td>
<td>Feed dialog</td>
<td>link opens page, no like count or context. You can pass customized description, image, etc for the story. Up to you to do a "thank you" page.</td>
<td>none</td>
</tr>
<tr>
<td>3</td>
<td>Feed via SDK</td>
<td>properly resized popup, JS control over the flow. No like count or context</td>
<td>Loading JS SDK</td>
</tr>
<tr>
<td>4</td>
<td>Like button in your frame</td>
<td>like count, social context, but no i18n resizing, comment option only sometimes</td>
<td>like.php iframe (3 requests)</td>
</tr>
<tr>
<td>5</td>
<td>Like button via SDK</td>
<td>All features plus proper resizing, comment dialog, easier to implement via fb:like tags in HTML</td>
<td>like.php + SDK</td>
</tr>
</table>
<p>I mentioned a few times in the article but let me repeat once again for the <em>TL;DR</em> folks. If you're loading the JS SDK, it's absolutely mandatory that you make sure it's either <a href="http://calendar.perfplanet.com/2011/the-art-and-craft-of-the-async-snippet/">loaded asynchronously</a> to avoid <a href="http://calendar.perfplanet.com/2011/frontend-spof-in-beijing/">SPOF</a>, or even better - <a href="https://www.facebook.com/note.php?note_id=10151176218703920">in an iframe</a> to <a href="http://calendar.perfplanet.com/2012/the-non-blocking-script-loader-pattern/">avoid blocking</a> <code>onload</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpied.com/speed-geeks-guide-to-facebook-buttons/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Run jsperf tests in a bunch of WebPagetest browsers</title>
		<link>http://www.phpied.com/jsperf-bookmarklet/</link>
		<comments>http://www.phpied.com/jsperf-bookmarklet/#comments</comments>
		<pubDate>Tue, 12 Feb 2013 03:24:03 +0000</pubDate>
		<dc:creator>Stoyan</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://www.phpied.com/?p=1688</guid>
		<description><![CDATA[Motivation 1. You write a new test to confirm a JavaScript-related performance speculation 2. You click 3. Your test runs in a bunch of browsers Glossary JSperf.com is the site where all you JavaScript performance guesswork should go to die or be confirmed. You know how the old wise people say "JSperf URL or it [...]]]></description>
				<content:encoded><![CDATA[<h2>Motivation</h2>
<p>1. You write a new test to confirm a JavaScript-related performance speculation<br />
2. You click<br />
3. Your test runs in a bunch of browsers</p>
<h2>Glossary</h2>
<p><a href="http://jsperf.com">JSperf.com</a> is the site where all you JavaScript performance guesswork should go to die or be confirmed. You know how the old wise people say "JSperf URL or it didn't happen! Now off my lawn!". Yup, that <a href="http://jsperf.com">jsperf.com</a></p>
<p><a href="http://webpagetest.org/">WebPagetest.org</a> (WPT) is the site where you get answers to the ol' question: "Why do people say my <em>oowsome</em> site is slow? And what should I do about it?"</p>
<p><em>Bookmarklet</em> is a little piece of JavaScript you conveniently access from your browser bookmarks and inject into other non-suspecting sites.</p>
<p><a href="http://github.com">Github</a> is where you host code.</p>
<p><a href="http://tools.w3clubs.com/bookmaker/">Bookmaker tool</a> makes a bookmarklet from a .js file URL (probably hosted on github)</p>
<h2>Trouble in paradise</h2>
<p>These days we're so happy and spoiled with all these amazing tools around us. And yet, when you create a JSPerf test, you have to open all these browsers and run the test everywhere. Even IE. And, when on Mac, IE is usually not readily available. Plus it comes in a bunch versions - from almost-but-not-quite-forgotten IE6, all the way to IE10 The Greatest - and they have different, sometimes contradicting, performance characterics.</p>
<h2>To the rescue: WPT</h2>
<p>WebPagetest has: a/ ability to run in a bunch of browsers and b/ <a href="https://sites.google.com/a/webpagetest.org/docs/advanced-features/webpagetest-restful-apis">an API</a></p>
<h2>The bookmarklet</h2>
<p>The bookmarklet. It's <a href="https://gist.github.com/stoyan/4759415">here, on github</a></p>
<p>It starts by inquiring about your WPT API key. I know, you have to get one. You can read the API docs on how to get one, but let me save you the trip: you just need to ask pmeenan@[the tool's domain].org for a key. Politely. Tell him I sent you. Promise not to abuse.</p>
<div class="hl-main">
<pre><span class="hl-code">  </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">key</span><span class="hl-code"> = </span><span class="hl-identifier">localStorage</span><span class="hl-code">.</span><span class="hl-identifier">wpt_key</span><span class="hl-code">;
  </span><span class="hl-reserved">if</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-code">!</span><span class="hl-identifier">key</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
    </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">prompt</span><span class="hl-code"> = </span><span class="hl-builtin">window</span><span class="hl-code">.</span><span class="hl-identifier">__proto__</span><span class="hl-code">.</span><span class="hl-identifier">prompt</span><span class="hl-code">;
    </span><span class="hl-identifier">key</span><span class="hl-code"> = </span><span class="hl-identifier">prompt</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">Your WebPageTest API key, please?</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;
    </span><span class="hl-reserved">if</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-code">!</span><span class="hl-identifier">key</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
      </span><span class="hl-reserved">return</span><span class="hl-code"> </span><span class="hl-identifier">gameOver</span><span class="hl-brackets">(</span><span class="hl-brackets">)</span><span class="hl-code">;
    </span><span class="hl-brackets">}</span><span class="hl-code">
    </span><span class="hl-identifier">localStorage</span><span class="hl-code">.</span><span class="hl-identifier">wpt_key</span><span class="hl-code"> = </span><span class="hl-identifier">key</span><span class="hl-code">;
  </span><span class="hl-brackets">}</span></pre>
</div>
<p>The key is stored in your <code>localStorage</code> so you don't have to paste it all the time.</p>
<p>Oh, you may wonder what's up with that:</p>
<div class="hl-main">
<pre><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">prompt</span><span class="hl-code"> = </span><span class="hl-builtin">window</span><span class="hl-code">.</span><span class="hl-identifier">__proto__</span><span class="hl-code">.</span><span class="hl-identifier">prompt</span><span class="hl-code">;
</span><span class="hl-identifier">prompt</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">Message...</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;</span></pre>
</div>
<p>Looks like something somewhere on jsperf is doing <code>window.prompt = function(){}</code>, same for <code>window.open</code> and probably others. Makes sense, you don't want popup-y stuff (by the thousands) while running a test a gazilion times. So the bookmarklet has to go the <code>window.__proto__</code> for the original <code>prompt</code></p>
<p>Moving on.</p>
<p>Setting up the constant params of the API call. The variable param will be the <code>location</code> which will tell what browser to use. We also give the (undocumented) <code>time</code> a value of 60s, so that the test has time to run. We also want only one run and just the first run (no full cache run).</p>
<p>The URL to test will be the current page loaded in jsperf.com which is where you run the bookmarklet. And we'll append <code>#run</code> for <a href="https://twitter.com/mathias/status/300027046510338048">autorun</a>.</p>
<div class="hl-main">
<pre><span class="hl-code">  </span><span class="hl-comment">//</span><span class="hl-comment"> base params</span><span class="hl-comment"></span><span class="hl-code">
  </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">wpt</span><span class="hl-code"> = </span><span class="hl-quotes">'</span><span class="hl-string">http://www.webpagetest.org/runtest.php?</span><span class="hl-quotes">'</span><span class="hl-code">;
  </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">params</span><span class="hl-code"> = </span><span class="hl-brackets">{</span><span class="hl-code">
    </span><span class="hl-identifier">k</span><span class="hl-code">: </span><span class="hl-identifier">key</span><span class="hl-code">,
    </span><span class="hl-identifier">time</span><span class="hl-code">: </span><span class="hl-number">60</span><span class="hl-code">,
    </span><span class="hl-identifier">runs</span><span class="hl-code">: </span><span class="hl-number">1</span><span class="hl-code">,
    </span><span class="hl-identifier">fvonly</span><span class="hl-code">: </span><span class="hl-number">1</span><span class="hl-code">,
    </span><span class="hl-identifier">url</span><span class="hl-code">: </span><span class="hl-quotes">'</span><span class="hl-string">http://jsperf.com</span><span class="hl-quotes">'</span><span class="hl-code"> + </span><span class="hl-identifier">location</span><span class="hl-code">.</span><span class="hl-identifier">pathname</span><span class="hl-code"> + </span><span class="hl-quotes">'</span><span class="hl-string">#run</span><span class="hl-quotes">'</span><span class="hl-code">
  </span><span class="hl-brackets">}</span><span class="hl-code">;
  </span><span class="hl-identifier">Object</span><span class="hl-code">
    .</span><span class="hl-identifier">keys</span><span class="hl-brackets">(</span><span class="hl-identifier">params</span><span class="hl-brackets">)</span><span class="hl-code">
    .</span><span class="hl-identifier">forEach</span><span class="hl-brackets">(</span><span class="hl-reserved">function</span><span class="hl-brackets">(</span><span class="hl-identifier">key</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
      </span><span class="hl-identifier">wpt</span><span class="hl-code"> += </span><span class="hl-identifier">key</span><span class="hl-code"> + </span><span class="hl-quotes">'</span><span class="hl-string">=</span><span class="hl-quotes">'</span><span class="hl-code"> + </span><span class="hl-identifier">encodeURIComponent</span><span class="hl-brackets">(</span><span class="hl-identifier">params</span><span class="hl-brackets">[</span><span class="hl-identifier">key</span><span class="hl-brackets">]</span><span class="hl-brackets">)</span><span class="hl-code"> + </span><span class="hl-quotes">'</span><span class="hl-string">&amp;</span><span class="hl-quotes">'</span><span class="hl-code">;
    </span><span class="hl-brackets">}</span><span class="hl-brackets">)</span><span class="hl-code">;</span></pre>
</div>
<p>Finally, setup the locations with browsers IE6,7,8,9,10 and open all these browser windows:</p>
<div class="hl-main">
<pre><span class="hl-code">  </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">locations</span><span class="hl-code"> = </span><span class="hl-identifier">localStorage</span><span class="hl-code">.</span><span class="hl-identifier">wpt_locations</span><span class="hl-code">;
  </span><span class="hl-reserved">if</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-code">!</span><span class="hl-identifier">locations</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
    </span><span class="hl-identifier">locations</span><span class="hl-code"> = </span><span class="hl-brackets">[</span><span class="hl-quotes">'</span><span class="hl-string">Dulles_IE6</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">Dulles_IE7</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">Dulles_IE8</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">Dulles_IE9</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">Dulles_IE10</span><span class="hl-quotes">'</span><span class="hl-brackets">]</span><span class="hl-code">;
  </span><span class="hl-brackets">}</span><span class="hl-code">
  
  </span><span class="hl-comment">//</span><span class="hl-comment"> pop some windows up</span><span class="hl-comment"></span><span class="hl-code">
  </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">open</span><span class="hl-code"> = </span><span class="hl-builtin">window</span><span class="hl-code">.</span><span class="hl-identifier">__proto__</span><span class="hl-code">.</span><span class="hl-identifier">open</span><span class="hl-code">;
  </span><span class="hl-identifier">locations</span><span class="hl-code">.</span><span class="hl-identifier">forEach</span><span class="hl-brackets">(</span><span class="hl-reserved">function</span><span class="hl-brackets">(</span><span class="hl-identifier">loco</span><span class="hl-brackets">)</span><span class="hl-brackets">{</span><span class="hl-code">
    </span><span class="hl-identifier">open</span><span class="hl-brackets">(</span><span class="hl-identifier">wpt</span><span class="hl-code"> + </span><span class="hl-quotes">'</span><span class="hl-string">location=</span><span class="hl-quotes">'</span><span class="hl-code"> + </span><span class="hl-identifier">encodeURIComponent</span><span class="hl-brackets">(</span><span class="hl-identifier">loco</span><span class="hl-brackets">)</span><span class="hl-brackets">)</span><span class="hl-code">;
  </span><span class="hl-brackets">}</span><span class="hl-brackets">)</span><span class="hl-code">;</span></pre>
</div>
<p>Again, the full source is <a href="https://gist.github.com/stoyan/4759415">here on github</a></p>
<p>Github has a "raw" version, <a href="https://gist.github.com/stoyan/4759415/raw/0d128dd0f6ea74be36ad505b1830e29b13ab34ff/jsperf-bookmarklet.js">e.g. this</a> so we take this url, paste it in the <a href="http://tools.w3clubs.com/bookmaker/">bookmaker tool</a> and we get a nice installable bookmarklet link.</p>
<h2>Install</h2>
<p>Drag this link to you bookmarks:</p>
<p><a href="javascript:(function(){var s = document.createElement('script'); s.src = 'https://gist.github.com/stoyan/4759415/raw/0d128dd0f6ea74be36ad505b1830e29b13ab34ff/jsperf-bookmarklet.js'; document.getElementsByTagName('head')[0].appendChild(s);})()">jsperf -&gt; wpt</a></p>
<h2>Run</h2>
<p>1. Go to any jsperf test, e.g. <a href="http://jsperf.com/array-proto-vs/3">http://jsperf.com/array-proto-vs/3</a><br />
2. Click the bookmarklet<br />
3. Observe 5 new tabs with 5 IE versions running your test!</p>
<p><img src="http://www.phpied.com/wp-content/uploads/2013/02/jsperf.jpg" alt="jsperf" width="558" height="315" class="aligncenter size-full wp-image-1689" /></p>
<h2>More browsers</h2>
<p>In addition to the browsers (locations) I've defined you can always add more, like Chrome and Firefox. However you probably have these already handy so no need to kill WPT's servers. But the option is there, just edit your <code>localStorage.wpt_locations</code></p>
<p>Thanks for reading! Comments welcome!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpied.com/jsperf-bookmarklet/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>webkit css-on-demand issues</title>
		<link>http://www.phpied.com/webkit-css-on-demand-issues/</link>
		<comments>http://www.phpied.com/webkit-css-on-demand-issues/#comments</comments>
		<pubDate>Mon, 11 Feb 2013 20:45:26 +0000</pubDate>
		<dc:creator>Stoyan</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://www.phpied.com/?p=1683</guid>
		<description><![CDATA[This post brought to you via Facebook engineers Jeff Morrison and Andrey Sukhachev, who discovered and helped isolate the issue. Use case Think a "single page app" use case. You click a button. Content comes via XHR. But content is complex (and app is as lazy-loading as possible) and content requires extra CSS. In an [...]]]></description>
				<content:encoded><![CDATA[<p>This post brought to you via Facebook engineers <a href="https://www.facebook.com/lbljeffmo">Jeff Morrison</a> and <a href="https://www.facebook.com/andrey.sukhachev">Andrey Sukhachev</a>, who discovered and helped isolate the issue.</p>
<h2>Use case</h2>
<p>Think a "single page app" use case. You click a button. Content comes via XHR. But content is complex (and app is as lazy-loading as possible) and content requires extra CSS. In an external file.</p>
<p>Only when the external CSS arrives should the app show the content. Otherwise content will be weirdly styled.</p>
<h2>Execution</h2>
<p>Two "modules" (or "widgets") of the app require two different CSS files. Both modules are requested at about the same time. We listen to <a href="http://www.phpied.com/when-is-a-stylesheet-really-loaded/" title="When is a stylesheet really loaded?">onload of the CSS files</a>. Expected behavior: whenever a module and its CSS dependency arrive - show that module. Asynchronously. No one cares which module shows first, as long as they show up as soon as possible.</p>
<h2>Experimentation</h2>
<p>Two modules. Two CSS files. 1st CSS happens to take one second. The second CSS takes 5 seconds.</p>
<p>Test pages: <a href="http://www.phpied.com/files/css-loading/style-onload.html">one</a> and <a href="http://www.phpied.com/files/css-loading/style-onload2.html">two</a></p>
<p>Here's the end result. The first module is pinky, the second is yellow. All good.</p>
<p><img src="http://www.phpied.com/files/css-loading/ss/end-result.jpg" alt="" /></p>
<p>Same with network panel ON:</p>
<p><img src="http://www.phpied.com/files/css-loading/ss/net.jpg" alt="" /></p>
<p>The question is what does the user see during the ?-mark - between the first CSS is done and the second one is still loading.</p>
<p>Oh, and here's the <code>load()</code> function that runs when the user clicks the button "load" initiating the new modules to appear:</p>
<div class="hl-main">
<pre><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">load</span><span class="hl-brackets">(</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
  </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">these</span><span class="hl-code"> = </span><span class="hl-brackets">[</span><span class="hl-quotes">'</span><span class="hl-string">class1.css.php</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">class2.css.php</span><span class="hl-quotes">'</span><span class="hl-brackets">]</span><span class="hl-code">;
  </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">classes</span><span class="hl-code"> = </span><span class="hl-brackets">[</span><span class="hl-quotes">'</span><span class="hl-string">class1</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">class2</span><span class="hl-quotes">'</span><span class="hl-brackets">]</span><span class="hl-code">;
  </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">head</span><span class="hl-code"> = </span><span class="hl-builtin">document</span><span class="hl-code">.</span><span class="hl-identifier">getElementsByTagName</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">head</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-brackets">[</span><span class="hl-number">0</span><span class="hl-brackets">]</span><span class="hl-code">;
  
  </span><span class="hl-reserved">for</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">i</span><span class="hl-code"> = </span><span class="hl-number">0</span><span class="hl-code">; </span><span class="hl-identifier">i</span><span class="hl-code"> &lt; </span><span class="hl-identifier">these</span><span class="hl-code">.</span><span class="hl-identifier">length</span><span class="hl-code">; </span><span class="hl-identifier">i</span><span class="hl-code">++</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
    </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">url</span><span class="hl-code"> = </span><span class="hl-identifier">these</span><span class="hl-brackets">[</span><span class="hl-identifier">i</span><span class="hl-brackets">]</span><span class="hl-code">;
    </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">link</span><span class="hl-code"> = </span><span class="hl-builtin">document</span><span class="hl-code">.</span><span class="hl-identifier">createElement</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">link</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;
    
    </span><span class="hl-identifier">link</span><span class="hl-code">.</span><span class="hl-identifier">type</span><span class="hl-code"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">text/css</span><span class="hl-quotes">&quot;</span><span class="hl-code">;
    </span><span class="hl-identifier">link</span><span class="hl-code">.</span><span class="hl-identifier">rel</span><span class="hl-code"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">stylesheet</span><span class="hl-quotes">&quot;</span><span class="hl-code">
    </span><span class="hl-identifier">link</span><span class="hl-code">.</span><span class="hl-identifier">href</span><span class="hl-code"> = </span><span class="hl-identifier">url</span><span class="hl-code">;
    </span><span class="hl-identifier">link</span><span class="hl-code">.</span><span class="hl-identifier">onload</span><span class="hl-code"> = </span><span class="hl-brackets">(</span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-identifier">i</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
      </span><span class="hl-reserved">return</span><span class="hl-code"> </span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
        </span><span class="hl-identifier">console</span><span class="hl-code">.</span><span class="hl-identifier">log</span><span class="hl-brackets">(</span><span class="hl-identifier">these</span><span class="hl-brackets">[</span><span class="hl-identifier">i</span><span class="hl-brackets">]</span><span class="hl-brackets">)</span><span class="hl-code">;
        </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">div</span><span class="hl-code"> = </span><span class="hl-builtin">document</span><span class="hl-code">.</span><span class="hl-identifier">createElement</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">div</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">
        </span><span class="hl-identifier">div</span><span class="hl-code">.</span><span class="hl-identifier">appendChild</span><span class="hl-brackets">(</span><span class="hl-builtin">document</span><span class="hl-code">.</span><span class="hl-identifier">createTextNode</span><span class="hl-brackets">(</span><span class="hl-identifier">these</span><span class="hl-brackets">[</span><span class="hl-identifier">i</span><span class="hl-brackets">]</span><span class="hl-brackets">)</span><span class="hl-brackets">)</span><span class="hl-code">;
        </span><span class="hl-identifier">result</span><span class="hl-code">.</span><span class="hl-identifier">appendChild</span><span class="hl-brackets">(</span><span class="hl-identifier">div</span><span class="hl-brackets">)</span><span class="hl-code">;
        </span><span class="hl-identifier">div</span><span class="hl-code">.</span><span class="hl-identifier">className</span><span class="hl-code"> = </span><span class="hl-identifier">classes</span><span class="hl-brackets">[</span><span class="hl-identifier">i</span><span class="hl-brackets">]</span><span class="hl-code">;
        </span><span class="hl-comment">//</span><span class="hl-comment">s = getComputedStyle(result).height;</span><span class="hl-comment"></span><span class="hl-code">
      </span><span class="hl-brackets">}</span><span class="hl-code">
    </span><span class="hl-brackets">}</span><span class="hl-brackets">(</span><span class="hl-identifier">i</span><span class="hl-brackets">)</span><span class="hl-brackets">)</span><span class="hl-code">;
    
    </span><span class="hl-identifier">head</span><span class="hl-code">.</span><span class="hl-identifier">appendChild</span><span class="hl-brackets">(</span><span class="hl-identifier">link</span><span class="hl-brackets">)</span><span class="hl-code">;
  </span><span class="hl-brackets">}</span><span class="hl-code">
 
</span><span class="hl-brackets">}</span></pre>
</div>
<h2>Expected behavior</h2>
<p>In FF, whenever the the first CSS is loaded, we see a new module.</p>
<p><img src="http://www.phpied.com/files/css-loading/ss/ff.jpg" alt="" /></p>
<p><a href="http://www.phpied.com/files/css-loading/style-onload.html">Test for yourself (in Firefox)</a></p>
<h2>#1 issue: "efficient" webkit</h2>
<p>You know that browsers batch layout and paints tasks because these tend to be expensive. For example they wait for all CSS (even useless print and other @media stylesheets) to arrive and block the rendering of the page. (More on these topics: <a href="http://www.phpied.com/5-years-later-print-css-still-sucks/">here</a>, <a href="http://www.phpied.com/css-and-the-critical-path/">here</a>)</p>
<p>So turns out that here webkit also waits for both CSS files to arrive before rendering anything.</p>
<p><img src="http://www.phpied.com/files/css-loading/ss/why.jpg" alt="" /></p>
<p>You see in the console we know (in JavaScript) that CSS has arrived. But webkit (chrome, safari, mobile safari) doesn't paint anything, waiting for the second CSS. Bummer!</p>
<h2>Issue #2: painting unstyled content</h2>
<p>While issue #1 is just a bummer that can be done better for the progressive feedback-y user experience, #2 is a bug. This is the issue that Jeff and Andrey found and were floored.</p>
<p>If there's a paint going on between the two stylesheets, the browser dumps the unstyled content on the page. Ugly stuff.</p>
<p><img src="http://www.phpied.com/files/css-loading/ss/bug.jpg" alt="" /></p>
<p>This was only happening sometimes, but after forming and testing an hypothesis, I was able to distill a reproducible test case. The only change is: after the load of the first CSS, <a href="http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/" title="Rendering: repaint, reflow/relayout, restyle">flush the rendering queue by requesting a style information</a>. e.g.</p>
<div class="hl-main">
<pre><span class="hl-identifier">link</span><span class="hl-code">.</span><span class="hl-identifier">onload</span><span class="hl-code"> = </span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
  </span><span class="hl-identifier">s</span><span class="hl-code"> = </span><span class="hl-identifier">getComputedStyle</span><span class="hl-brackets">(</span><span class="hl-identifier">dom</span><span class="hl-brackets">)</span><span class="hl-code">.</span><span class="hl-identifier">height</span><span class="hl-code">;
</span><span class="hl-brackets">}</span></pre>
</div>
<h2>Repro and file a bug</h2>
<p>You can reproduce for yourself. Use chrome and try:</p>
<ol>
<li><a href="http://www.phpied.com/files/css-loading/style-onload.html">Issue: no paint till all CSS is here</a></li>
<li><a href="http://www.phpied.com/files/css-loading/style-onload2.html">Bug: unstyled paint while waiting for all CSS</a></li>
</ol>
<p>I was faced with "registration wall" trying to file a webkit bug, hence this post. Someone please file a bug and feel free to use the provided test cases.</p>
<p>The solution, IMO, is to make webkit behave like FF. No waiting for all CSS. This solves both issues. In the worst case, at least the unstyled bug (issue #2) should be addressed.</p>
<p>Interim solution for web developers: inline CSS required by the module together with the module content.</p>
<p>Thanks for reading!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpied.com/webkit-css-on-demand-issues/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Digging into the HTTP archive #2</title>
		<link>http://www.phpied.com/digging-into-the-http-archive-2/</link>
		<comments>http://www.phpied.com/digging-into-the-http-archive-2/#comments</comments>
		<pubDate>Sat, 29 Dec 2012 04:43:10 +0000</pubDate>
		<dc:creator>Stoyan</dc:creator>
				<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://www.phpied.com/?p=1680</guid>
		<description><![CDATA[Continuing from earlier tonight, let's see how you can use the HTTP archive as a starting point and continue examining the Internet at large. Task: figure out what % of the JPEGs out there on the web today are progressive vs baseline. Ann Robson has an article for the perfplanet calendar later tonight with all [...]]]></description>
				<content:encoded><![CDATA[<p>Continuing from earlier <a href="http://www.phpied.com/digging-into-the-http-archive/">tonight</a>, let's see how you can use the <a href="http://httparchive.org">HTTP archive</a> as a starting point and continue examining the Internet at large.</p>
<p>Task: figure out what % of the JPEGs out there on the web today are <a href="http://yuiblog.com/blog/2008/12/05/imageopt-4/">progressive vs baseline</a>. <a href="http://www.htmlhive.com/">Ann Robson</a> has an article for the <a href="http://calendar.perfplanet.com">perfplanet calendar</a> later tonight with all the juicy details.</p>
<p>Problemo: there's no such information in HTTPArchive. However there's table <code>requests</code> with a list of URLs as you can see in the previous post.</p>
<p>Solution: Get a list of 1000 random jpegs (mimeType='image/jpeg'), download them all and run <a href="http://www.imagemagick.org">imagemagick</a>'s <code>identify</code> to figure out the percentage.</p>
<h2>How?</h2>
<p>You have a copy of the DB as described in the previous post. Now connect to mysql (assuming you have an alias by now):</p>
<pre>$ mysql -u root httparchive</pre>
<p>Now just for kicks, let's get one jpeg:</p>
<pre>mysql&gt; select requestid, url, mimeType from requests \
    where mimeType = 'image/jpeg' limit 1;
+-----------+--------------------------------------------+------------+
| requestid | url                                        | mimeType   |
+-----------+--------------------------------------------+------------+
| 404421629 | http://www.studymode.com/education-blog....| image/jpeg |
+-----------+--------------------------------------------+------------+
1 row in set (0.01 sec)
</pre>
<p>Looks promising.</p>
<p>Now let's fetch 1000 random images, while at the same time dump them into a file. For convenience let's make this file a shell script so it's easy to run. And the contents will be one curl command per line. Let's use mysql to do all the string concatenation.</p>
<p>Testing with one image:</p>
<pre>
mysql&gt; select concat('curl -o ', requestid, '.jpg "', url, '"') from requests\
    where mimeType = 'image/jpeg' limit 1;
+-----------------------------------------------------------+
| concat('curl -o ', requestid, '.jpg "', url, '"')         |
+-----------------------------------------------------------+
| curl -o 404421629.jpg "http://www.studymode.com/educ..."  |
+-----------------------------------------------------------+
1 row in set (0.00 sec)
</pre>
<p>All looks good. I'm using the requestid as file name, so the experiment is always reproducible.</p>
<div class="hl-main">
<pre><span class="hl-identifier">mysql</span><span class="hl-code">&gt;
 </span><span class="hl-reserved">SELECT</span><span class="hl-code"> </span><span class="hl-reserved">concat</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">curl -o </span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-identifier">requestid</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">.jpg &quot;</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-identifier">url</span><span class="hl-code">, </span><span class="hl-quotes">'</span><span class="hl-string">&quot;</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code"> 
  </span><span class="hl-reserved">INTO</span><span class="hl-code"> </span><span class="hl-reserved">OUTFILE</span><span class="hl-code"> </span><span class="hl-quotes">'</span><span class="hl-string">/tmp/jpegs.sh</span><span class="hl-quotes">'</span><span class="hl-code"> 
  </span><span class="hl-reserved">LINES</span><span class="hl-code"> </span><span class="hl-reserved">TERMINATED</span><span class="hl-code"> </span><span class="hl-reserved">BY</span><span class="hl-code"> </span><span class="hl-quotes">'</span><span class="hl-special">\n</span><span class="hl-quotes">'</span><span class="hl-code"> </span><span class="hl-reserved">FROM</span><span class="hl-code"> </span><span class="hl-identifier">requests</span><span class="hl-code">
  </span><span class="hl-reserved">WHERE</span><span class="hl-code"> </span><span class="hl-identifier">mimeType</span><span class="hl-code"> = </span><span class="hl-quotes">'</span><span class="hl-string">image/jpeg</span><span class="hl-quotes">'</span><span class="hl-code">
  </span><span class="hl-reserved">ORDER</span><span class="hl-code"> </span><span class="hl-reserved">by</span><span class="hl-code"> </span><span class="hl-reserved">rand</span><span class="hl-brackets">(</span><span class="hl-brackets">)</span><span class="hl-code"> 
  </span><span class="hl-reserved">LIMIT</span><span class="hl-code"> </span><span class="hl-number">1000</span><span class="hl-code">;</span></pre>
</div>
<pre>Query OK, 1000 rows affected (2 min 25.04 sec)</pre>
<p>Lo and behold, three minutes later, we have generated a shell script in <code>/tmp/jpegs.sh</code> that looks like:</p>
<pre>curl -o 422877532.jpg "http://www.friendster.dk/file/pic/user/SellDiablo_60.jpg"
curl -o 406113210.jpg "http://profile.ak.fbcdn.net/hprofile-ak-ash4/370543_100004326543130_454577697_q.jpg"
curl -o 423577106.jpg "http://www.moreliainvita.com/Banner_index/Cantinelas.jpg"
curl -o 429625174.jpg "http://newnews.ca/apics/92964906IMG_9424--1.jpg"
....</pre>
<p>Now, nothing left to do but run this script and download a bunch of images:</p>
<pre>$ mkdir /tmp/jpegs
$ sh ../jpegs.sh</pre>
<p>curl output flashes by and some minutes later you have almost 1000 images, mostly NSFW. Not 1000 because of timeouts, unreachable hosts, etc.</p>
<pre>$ ls | wc -l
     983</pre>
<p>Now back to the original task: how many baseline and how many progressive JPEGs:</p>
<pre>$ identify -verbose *.jpg | grep "Interlace: None" | wc -l
     XXX
$ identify -verbose *.jpg | grep "Interlace: JPEG" | wc -l
     YYY</pre>
<p>For the actual values of XXX and YYY, check Ann's post later tonight <img src='http://www.phpied.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Also turns out 983 - XXX - YYY = 26 because some of the downloaded images were not really images, but 404 pages and other non-image files.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpied.com/digging-into-the-http-archive-2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Digging into the HTTP archive</title>
		<link>http://www.phpied.com/digging-into-the-http-archive/</link>
		<comments>http://www.phpied.com/digging-into-the-http-archive/#comments</comments>
		<pubDate>Sat, 29 Dec 2012 01:00:40 +0000</pubDate>
		<dc:creator>Stoyan</dc:creator>
				<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://www.phpied.com/?p=1677</guid>
		<description><![CDATA[Update: Second part One way to do web performance research is to dig into what's out there. It's a tradition dating back from Steve Souders and his HPWS where he was looking at the top 10 Alexa sites for proof that best practices are or aren't followed. This involves loading each pages and inspecting the [...]]]></description>
				<content:encoded><![CDATA[<p><b>Update:</b> <a href="http://www.phpied.com/digging-into-the-http-archive-2/">Second part</a></p>
<p>One way to do web performance research is to dig into what's out there. It's a tradition dating back from <a href="http://stevesouders.com">Steve Souders</a> and his <a href="http://www.amazon.com/dp/0596529309/?tag=w3clubs-20">HPWS</a> where he was looking at the top 10 Alexa sites for proof that best practices are or aren't followed. This involves loading each pages and inspecting the body or the response headers. Pros: real sites. Cons: manual labor, small sample.</p>
<p>I've done some image and CSS optimization research grabbing data in any way that looks easy: using the Yahoo <a href="http://yuiblog.com/blog/2008/12/05/imageopt-4/">image search API to get URLs</a> or <a href="http://www.slideshare.net/stubbornella/5-mistakes-of-massive-css">using Fiddler</a> to monitor and export the traffic and loading <a href="http://www.bookofspeed.com/chapter5.html">a bazillion sites</a> in IE with a script. Or <a href="http://www.phpied.com/httpwatch-automation-javascript/">using HTTPWatch</a>. Pros: big sample. Cons: reinvent the wheel and use a different sampling criteria every time.</p>
<p>Today we have <a href="http://httparchive.org">httparchive.org</a> which makes performance research so much easier. It already has a bunch of data you can export and dive into immediately. It's also a common starting point so two people can examine the same data independently and compare or reproduce each other's results.</p>
<p>Let's see how to get started with the HTTP archive's data.</p>
<p><img src="http://www.phpied.com/wp-content/uploads/2012/12/3sd8y3.jpeg" alt="speak it" width="625" height="439" /></p>
<p>(Assuming MacOS, but the differences with other OS are negligible)</p>
<p>1. <a href="http://dev.mysql.com/doc/refman/5.0/en/macosx-installation.html">Install MySQL</a><br />
2. Your mysql binary will be in <code>/usr/local/mysql/bin/mysql</code>. Feel free to create an alias. Your username is <code>root</code> and no password. This is of course terribly insecure but for a local machine with no important data, it's probably tolerable. Connect:</p>
<pre>$ /usr/local/mysql/bin/mysql -u root</pre>
<p>You'll see some text and a friendly cursor:</p>
<pre>...
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql&gt;
</pre>
<p>3. Create your new shiny database:</p>
<pre>mysql&gt; create database httparchive;
Query OK, 1 row affected (0.00 sec)</pre>
<p>Look into the new DB, it's empty, no tables or data, as expected:</p>
<pre>mysql&gt; \u httparchive
Database changed
mysql&gt; show tables;
Empty set (0.00 sec)</pre>
<p>4. Quit mysql for now:</p>
<pre>mysql&gt; quit;
Bye</pre>
<p>5. Go the <a href="http://httparchive.org/downloads.php">archive</a> and fetch <a href="http://httparchive.org/downloads/httparchive_schema.sql">the database schema</a>.</p>
<pre>$ curl http://httparchive.org/downloads/httparchive_schema.sql &gt; ~/Downloads/schema.sql</pre>
<p>While you're there get the latest DB dump. That would be the link that says <strong>IE</strong>. Today it says <strong>Dec 15</strong> and is 2.5GB. So be prepared. Save it and unzip it as, say, <code>~/Downloads/dump.sql</code></p>
<p>6. Recreate the DB tables:</p>
<pre>$ /usr/local/mysql/bin/mysql -u root httparchive &lt; ~/Downloads/schema.sql</pre>
<p>7. Import the data (takes a while):</p>
<pre>$ /usr/local/mysql/bin/mysql -u root httparchive &lt; ~/Downloads/dump.sql</pre>
<p>8. Log back into mysql and look around:</p>
<pre>$ /usr/local/mysql/bin/mysql -u root httparchive;

[yadda, yadda...]

mysql&gt; show tables;
+-----------------------+
| Tables_in_httparchive |
+-----------------------+
| pages                 |
| pagesmobile           |
| requests              |
| requestsmobile        |
| stats                 |
+-----------------------+
5 rows in set (0.00 sec)
</pre>
<p>Dataaaa!</p>
<p>What's in the <code>requests</code> table <em>I couldn't help but wonder</em> (damn you, SATC)</p>
<pre>mysql&gt; describe requests;
+------------------------+------------------+------+-----+---------+----------------+
| Field                  | Type             | Null | Key | Default | Extra          |
+------------------------+------------------+------+-----+---------+----------------+
| requestid              | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| pageid                 | int(10) unsigned | NO   | MUL | NULL    |                |
| startedDateTime        | int(10) unsigned | YES  | MUL | NULL    |                |
| time                   | int(10) unsigned | YES  |     | NULL    |                |
| method                 | varchar(32)      | YES  |     | NULL    |                |
| url                    | text             | YES  |     | NULL    |                |
| urlShort               | varchar(255)     | YES  |     | NULL    |                |
| redirectUrl            | text             | YES  |     | NULL    |                |
| firstReq               | tinyint(1)       | NO   |     | NULL    |                |
| firstHtml              | tinyint(1)       | NO   |     | NULL    |                |
| reqHttpVersion         | varchar(32)      | YES  |     | NULL    |                |
| reqHeadersSize         | int(10) unsigned | YES  |     | NULL    |                |
| reqBodySize            | int(10) unsigned | YES  |     | NULL    |                |
| reqCookieLen           | int(10) unsigned | NO   |     | NULL    |                |
| reqOtherHeaders        | text             | YES  |     | NULL    |                |
| status                 | int(10) unsigned | YES  |     | NULL    |                |
| respHttpVersion        | varchar(32)      | YES  |     | NULL    |                |
| respHeadersSize        | int(10) unsigned | YES  |     | NULL    |                |
| respBodySize           | int(10) unsigned | YES  |     | NULL    |                |
| respSize               | int(10) unsigned | YES  |     | NULL    |                |
| respCookieLen          | int(10) unsigned | NO   |     | NULL    |                |
| mimeType               | varchar(255)     | YES  |     | NULL    |                |
.....
</pre>
<p>Hm, I wonder what are common mime types these days. Limiting to 10000 or more occurrences of the same mime type, because there's a lot of garbage out there. If you've never looked into real web data, you'd surprised how much misconfiguration is going on. It's a small miracle the web even works.</p>
<p>9. Most common mime types:</p>
<div class="hl-main">
<pre><span class="hl-reserved">select</span><span class="hl-code"> </span><span class="hl-reserved">count</span><span class="hl-brackets">(</span><span class="hl-identifier">requestid</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-reserved">as</span><span class="hl-code"> </span><span class="hl-identifier">ct</span><span class="hl-code">, </span><span class="hl-identifier">mimeType</span><span class="hl-code"> 
  </span><span class="hl-reserved">from</span><span class="hl-code"> </span><span class="hl-identifier">requests</span><span class="hl-code"> 
  </span><span class="hl-reserved">group</span><span class="hl-code"> </span><span class="hl-reserved">by</span><span class="hl-code"> </span><span class="hl-identifier">mimeType</span><span class="hl-code"> 
  </span><span class="hl-reserved">having</span><span class="hl-code"> </span><span class="hl-identifier">ct</span><span class="hl-code"> &gt; </span><span class="hl-number">10000</span><span class="hl-code"> 
  </span><span class="hl-reserved">order</span><span class="hl-code"> </span><span class="hl-reserved">by</span><span class="hl-code"> </span><span class="hl-identifier">ct</span><span class="hl-code"> </span><span class="hl-reserved">desc</span><span class="hl-code">;</span></pre>
</div>
<pre>
+---------+-------------------------------+
| ct      | mimeType                      |
+---------+-------------------------------+
| 7448471 | image/jpeg                    |
| 4640536 | image/gif                     |
| 4293966 | image/png                     |
| 2843749 | text/html                     |
| 1837887 | application/x-javascript      |
| 1713899 | text/javascript               |
| 1455097 | text/css                      |
| 1093004 | application/javascript        |
|  619605 |                               |
|  343018 | application/x-shockwave-flash |
|  188799 | image/x-icon                  |
|  169928 | text/plain                    |
|   70226 | text/xml                      |
|   50439 | font/eot                      |
|   45416 | application/xml               |
|   41052 | application/octet-stream      |
|   38618 | application/json              |
|   30201 | text/x-cross-domain-policy    |
|   25248 | image/vnd.microsoft.icon      |
|   20513 | image/jpg                     |
|   12854 | application/vnd.ms-fontobject |
|   11788 | image/pjpeg                   |
+---------+-------------------------------+
22 rows in set (2 min 25.18 sec)</pre>
<p>So the web is mostly made of JPEGs. GIFs are still more than PNGs despite <a href="http://givepngachance.com/">all best efforts</a>. Although OTOH (assuming these are comparable datasets), PNG is definitely gaining compared to <a href="http://www.bookofspeed.com/images/05.04.top1000.png">this picture</a> from two and a half <a href="http://www.bookofspeed.com/chapter5.html">years ago</a>. Anyway.</p>
<h2>It's <em>you</em> time!</h2>
<p>So this is how easy it is to get started with the HTTPArchive. What experiment would you run with this data?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpied.com/digging-into-the-http-archive/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Deck the Halls 2012</title>
		<link>http://www.phpied.com/deck-the-halls-2012/</link>
		<comments>http://www.phpied.com/deck-the-halls-2012/#comments</comments>
		<pubDate>Tue, 25 Dec 2012 02:46:53 +0000</pubDate>
		<dc:creator>Stoyan</dc:creator>
				<category><![CDATA[Music]]></category>

		<guid isPermaLink="false">http://www.phpied.com/?p=1674</guid>
		<description><![CDATA[Traditions are traditions. Marry Christmas with a new cover, this time it's Deck the Halls: Deck the halls (part one) (It's only part one because I didn't find the time to properly record what I had in mind - another 7/8th cover like last year. But you can hear the idea at the end) Here [...]]]></description>
				<content:encoded><![CDATA[<p><img src="http://www.phpied.com/wp-content/uploads/2012/12/wineguitar.jpg" alt="wineguitar" width="650" height="963" /></p>
<p>Traditions are traditions. Marry Christmas with a new cover, this time it's <em>Deck the Halls</em>:</p>
<p><a href="http://www.phpied.com/files/music/decks%20the%20hallses.mp3">Deck the halls (part one)</a></p>
<p>(It's only part one because I didn't find the time to properly record what I had in mind - another 7/8th cover like last year. But you can hear the idea at the end)</p>
<p>Here are the previous years for your entertainment.</p>
<ul>
<li><a href="/files/music/we-wish-7:8:9:8.mp3">We Wish You a Merry Christmas (7/8th and 9/8th)</a></li>
<li><a href="/files/music/feliz-navidad.mp3">Feliz Navidad 2009</a></li>
<li><a href="/files/music/jingle-bell.mp3">Jingle Bells 2008</a></li>
</ul>
<p>Here's to a happy new 2013!</p>
<hr />
<p>Gear: Ovation wine-colored guitar (depicted above) plugged in one channel of M-Audio box. AKG C452 microphone ponited at 12th fret and plugged in the other channel of the M-Audio box. Out of the box and into Garageband.</p>
<p><script src="http://mediaplayer.yahoo.com/js"></script></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpied.com/deck-the-halls-2012/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
<enclosure url="http://www.phpied.com/files/music/decks%20the%20hallses.mp3" length="1837266" type="audio/mpeg" />
		</item>
		<item>
		<title>WebAudio: live input</title>
		<link>http://www.phpied.com/webaudio-live-input/</link>
		<comments>http://www.phpied.com/webaudio-live-input/#comments</comments>
		<pubDate>Sun, 28 Oct 2012 09:08:26 +0000</pubDate>
		<dc:creator>Stoyan</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Music]]></category>
		<category><![CDATA[WebAudio]]></category>

		<guid isPermaLink="false">http://www.phpied.com/?p=1669</guid>
		<description><![CDATA[Live input, aka getUserMedia: it exists in Chrome Canary for audio too. Great times to be a web developer, right? Let's check it out. Here's the demo, but first a prerequisite: go chrome://flags, search for "Web Audio Input" and enable it. Restart Chrome Canary. With a guitar I wanted to have a little trickier setup [...]]]></description>
				<content:encoded><![CDATA[<p>Live input, aka <code>getUserMedia</code>: it exists in Chrome Canary for audio too. Great times to be a web developer, right?</p>
<p>Let's check it out.</p>
<p><a href="http://www.phpied.com/files/webaudio/getusermedia.html">Here's the demo</a>, but first a prerequisite: go <a href="chrome://flags">chrome://flags</a>, search for "Web Audio Input" and enable it. Restart Chrome Canary.</p>
<h3>With a guitar</h3>
<p>I wanted to have a little trickier setup and capture guitar sound not just voice with a microphone.</p>
<p>As always, it was bigger hurdle to get guitar sound to the computer, than anything else JavaScript-wise.</p>
<p>I have a guitar amp that has a mini-USB out. This goes to the USB of the computer. Wrestle, system settings, garage band to the rescue.... eventually the computer makes sound. </p>
<h3>Capturing</h3>
<p>I was assuming the stream you get from <code>getuserMedia</code> can go directly to an HTML <code>&lt;audio&gt; src</code>. No such luck. <a href="http://www.phpied.com/canvas-pixels-3-getusermedia/">Works for video</a> but <a href="http://code.google.com/p/chromium/issues/detail?id=112367">not yet for audio</a>.</p>
<p>So... WebAudio API saves the day.</p>
<p>Setting up audio context (like in the previous post), shimming getUserMedia and setting up callbacks for it:</p>
<div class="hl-main">
<pre><span class="hl-code">  </span><span class="hl-comment">//</span><span class="hl-comment"> for logging</span><span class="hl-comment"></span><span class="hl-code">
  </span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">fire</span><span class="hl-brackets">(</span><span class="hl-identifier">e</span><span class="hl-code">, </span><span class="hl-identifier">data</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">    
    </span><span class="hl-identifier">log</span><span class="hl-code">.</span><span class="hl-identifier">innerHTML</span><span class="hl-code"> += </span><span class="hl-quotes">&quot;</span><span class="hl-special">\n</span><span class="hl-quotes">&quot;</span><span class="hl-code"> + </span><span class="hl-identifier">e</span><span class="hl-code"> + </span><span class="hl-quotes">&quot;</span><span class="hl-string"> </span><span class="hl-quotes">&quot;</span><span class="hl-code"> + </span><span class="hl-brackets">(</span><span class="hl-identifier">data</span><span class="hl-code"> || </span><span class="hl-quotes">'</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;
  </span><span class="hl-brackets">}</span><span class="hl-code">
 
  </span><span class="hl-comment">//</span><span class="hl-comment"> globals</span><span class="hl-comment"></span><span class="hl-code">
  </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">audio_context</span><span class="hl-code">;
  </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">volume</span><span class="hl-code">;
 
  </span><span class="hl-comment">//</span><span class="hl-comment"> one-off initialization</span><span class="hl-comment"></span><span class="hl-code">
  </span><span class="hl-brackets">(</span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">init</span><span class="hl-brackets">(</span><span class="hl-identifier">g</span><span class="hl-brackets">)</span><span class="hl-brackets">{</span><span class="hl-code">
    </span><span class="hl-reserved">try</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
      </span><span class="hl-identifier">audio_context</span><span class="hl-code"> = </span><span class="hl-reserved">new</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-identifier">g</span><span class="hl-code">.</span><span class="hl-identifier">AudioContext</span><span class="hl-code"> || </span><span class="hl-identifier">g</span><span class="hl-code">.</span><span class="hl-identifier">webkitAudioContext</span><span class="hl-brackets">)</span><span class="hl-code">;
      </span><span class="hl-identifier">fire</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">Audio context OK</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;
      </span><span class="hl-comment">//</span><span class="hl-comment"> shim</span><span class="hl-comment"></span><span class="hl-code">
      </span><span class="hl-builtin">navigator</span><span class="hl-code">.</span><span class="hl-identifier">getUserMedia</span><span class="hl-code"> = </span><span class="hl-builtin">navigator</span><span class="hl-code">.</span><span class="hl-identifier">getUserMedia</span><span class="hl-code"> || </span><span class="hl-builtin">navigator</span><span class="hl-code">.</span><span class="hl-identifier">webkitGetUserMedia</span><span class="hl-code">;
      </span><span class="hl-identifier">fire</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">navigator.getUserMedia </span><span class="hl-quotes">'</span><span class="hl-code"> + </span><span class="hl-brackets">(</span><span class="hl-builtin">navigator</span><span class="hl-code">.</span><span class="hl-identifier">getUserMedia</span><span class="hl-code"> ? </span><span class="hl-quotes">'</span><span class="hl-string">OK</span><span class="hl-quotes">'</span><span class="hl-code"> : </span><span class="hl-quotes">'</span><span class="hl-string">fail</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-brackets">)</span><span class="hl-code">;
      </span><span class="hl-comment">//</span><span class="hl-comment"> use</span><span class="hl-comment"></span><span class="hl-code">
      </span><span class="hl-builtin">navigator</span><span class="hl-code">.</span><span class="hl-identifier">getUserMedia</span><span class="hl-brackets">(</span><span class="hl-code">
        </span><span class="hl-brackets">{</span><span class="hl-identifier">audio</span><span class="hl-code">:</span><span class="hl-reserved">true</span><span class="hl-brackets">}</span><span class="hl-code">,
        </span><span class="hl-identifier">iCanHazUserMedia</span><span class="hl-code">, 
        </span><span class="hl-reserved">function</span><span class="hl-brackets">(</span><span class="hl-identifier">e</span><span class="hl-brackets">)</span><span class="hl-brackets">{</span><span class="hl-identifier">fire</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">No live audio input </span><span class="hl-quotes">'</span><span class="hl-code"> + </span><span class="hl-identifier">e</span><span class="hl-brackets">)</span><span class="hl-code">;</span><span class="hl-brackets">}</span><span class="hl-code">
      </span><span class="hl-brackets">)</span><span class="hl-code">;
    </span><span class="hl-brackets">}</span><span class="hl-code"> </span><span class="hl-reserved">catch</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-identifier">e</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
      </span><span class="hl-identifier">alert</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">No web audio support in this browser</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;
    </span><span class="hl-brackets">}</span><span class="hl-code">
  </span><span class="hl-brackets">}</span><span class="hl-brackets">(</span><span class="hl-builtin">window</span><span class="hl-brackets">)</span><span class="hl-brackets">)</span><span class="hl-code">;</span></pre>
</div>
<p>When the user loads the page, here's what they see:</p>
<p><img src="http://www.phpied.com/wp-content/uploads/2012/10/Live-input.jpg" alt="" title="Live input" width="650" height="271" class="aligncenter size-full wp-image-1670" /></p>
<p>In my case I select the guitar amp and click "Allow" button.</p>
<p>This little window informs me the page is using the audio input:</p>
<p><img src="http://www.phpied.com/wp-content/uploads/2012/10/SystemUIServer.jpg" alt="" title="SystemUIServer" width="332" height="131" class="aligncenter size-full wp-image-1671" /></p>
<h3>Playing back</h3>
<p>Now that the user has allowed audio access, let's play back the audio we receive, but pass it through a volume control.</p>
<p>All this work happens in the <code>iCanhazUserMedia()</code>, the success callback to <code>getUserMedia</code>.</p>
<div class="hl-main">
<pre><span class="hl-code">  </span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">iCanHazUserMedia</span><span class="hl-brackets">(</span><span class="hl-identifier">stream</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code">
    
    </span><span class="hl-identifier">fire</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">I haz live stream</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;
    
    </span><span class="hl-reserved">var</span><span class="hl-code"> </span><span class="hl-identifier">input</span><span class="hl-code"> = </span><span class="hl-identifier">audio_context</span><span class="hl-code">.</span><span class="hl-identifier">createMediaStreamSource</span><span class="hl-brackets">(</span><span class="hl-identifier">stream</span><span class="hl-brackets">)</span><span class="hl-code">;
    </span><span class="hl-identifier">volume</span><span class="hl-code"> = </span><span class="hl-identifier">audio_context</span><span class="hl-code">.</span><span class="hl-identifier">createGainNode</span><span class="hl-brackets">(</span><span class="hl-brackets">)</span><span class="hl-code">;
    </span><span class="hl-identifier">volume</span><span class="hl-code">.</span><span class="hl-identifier">gain</span><span class="hl-code">.</span><span class="hl-identifier">value</span><span class="hl-code"> = </span><span class="hl-number">0.8</span><span class="hl-code">;
    </span><span class="hl-identifier">input</span><span class="hl-code">.</span><span class="hl-identifier">connect</span><span class="hl-brackets">(</span><span class="hl-identifier">volume</span><span class="hl-brackets">)</span><span class="hl-code">;
    </span><span class="hl-identifier">volume</span><span class="hl-code">.</span><span class="hl-identifier">connect</span><span class="hl-brackets">(</span><span class="hl-identifier">audio_context</span><span class="hl-code">.</span><span class="hl-identifier">destination</span><span class="hl-brackets">)</span><span class="hl-code">;
    
    </span><span class="hl-identifier">fire</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">input connected to destination</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;
  </span><span class="hl-brackets">}</span></pre>
</div>
<p>What we have here (ignoring <code>fire()</code>):</p>
<ol>
<li>setup an input stream from the user stream, this is the first node in the audio chain</li>
<li>setup a volume (Gain) node with initial volume 0.8 out of 1</li>
<li>connect input to volume to output/speakers</li>
</ol>
<p>And this is it!</p>
<p>Additionally an <code>input type=range max=1 step=0.1</code> can change the volume via <code>volume.gain.value = value;</code></p>
<p><a href="http://www.phpied.com/files/webaudio/getusermedia.html">Go play!</a> Isn't it amazing that you can now grab microphone or any other audio input and play around with it? All in JavaScript, all in the browser without any plugins.</p>
<h3>Moar!</h3>
<p>This was a very basic exploratory/primer example. For more:</p>
<ul>
<li><a href="http://dashersw.github.com/pedalboard.js/demo/">Pedalboard.js</a> with more effects besides volume</li>
<li>One of Chris Wilson's demos has <a href="http://webaudiodemos.appspot.com/input/index.html">even more effects</a></li>
<li>and how 'bout <a href="http://phenomnomnominal.github.com/">a guitar tuna</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.phpied.com/webaudio-live-input/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>
