Google adds site speed to search ranking

April 9, 2010 7:46 am | 12 Comments

Today, Google announced that a site’s speed has been added as a signal to Google’s search ranking algorithm: Using site speed in web search ranking.

In March 2008, one month after I started working here, Google announced that site speed was being incorporated into Adwords Quality Score. When I wrote my blog post about that change to Adwords (Google fosters a faster Internet) I had no idea that this was the beginning of a long series of contributions from Google for creating a faster Web. Since that time Google has released:

Two years ago when I talked to people about the Adwords change, most people thought it was a good idea, but the most frequent response was, “Doesn’t this favor larger companies that care about performance?” In my experience, small companies that care about performance are able to make improvements much more quickly than large companies. Small companies are typically more agile and have less legacy code to worry about.

I’m excited to see web performance optimization become a competitive advantage, and look forward to helping web developers around the world make their sites even faster. Make sure to run Page Speed and YSlow to find the most important performance improvements. If you still have questions, feel free to contact me. I’ll be happy to analyze your web site and give you some tips.

As much as I’m excited about how Google’s announcement raises awareness about web performance optimization among companies and developers, I’m most excited about what this means for users. Faster web sites lead to a better user experience. And that’s what it’s all about.

12 Comments

Speed Doesn’t Matter

April 1, 2010 9:33 am | 16 Comments

[Note the date this blog post was written.]

Six years. Wasted.

That’s how I’m feeling after reading a recent performance-related article from WebSundries.com. The article reviews the results of various performance changes made to their web site, and the impact it had on their business. Although the improvements did in fact improve several metrics, at the end of the day they found it didn’t matter than much

The conclusions are a surprise, to say the least. But DeWitt Leighter, WebSundries’ VP of Engineering who authored the article, brought up several good points to support their interpretation of the data:

Focusing on improving the speed of our web site did have benefits. Conversions increased by 27%. Unique users nearly doubled (97% increase), and session length increased from 12 to 19 minutes. But the costs to achieve this were also significant, and in our interpretation outweighed the benefits.

Among the costs of improving their web site performance was the development effort. Later Leighter described how their developers were burdened by having to learn how to program, and worry about the impact of their changes. Leighter says this was an unsustainable cost with no end in sight. The result?

We’ve gone full circle. The entire front page is now a single image. We use a technique called image maps to take the user directly to the product they wish to purchase. We reduced the size of our HTML document from nearly 17 kB to just under 200 bytes, and that’s before compression.

In response to the increases in conversions and users, DeWitt cited the fact that revenue was not one of their key business metrics, and user satisfaction was hard to measure and thus easy to ignore. When asked about the impact of downloading their 26 MB image map on mobile devices, Leighter recalled recent studies that show bandwidth is increasing and mobile usage is on the decline. As evidence he cited the fact that their web logs show almost no mobile users.

Chilling results to say the least. I’ll be watching closely to see how this alternative approach to web site performance plays out for WebSundries.com.

About WebSundries.com

WebSundries.com has been the destination for shoppers for nearly two centuries. Starting in 1826 as Leighter’s Dry Goods and Mercantile, they’re perhaps best known for their heavy investment in vacuum tubes and rotary phones, for which they still hold the world’s largest inventories. Rebranded as WebSundries.com in 1998, the company boasts having one of the most consistent customer bases on the Internet, with almost no change since they first launched their site.

16 Comments

P3PC: Google AdSense

March 29, 2010 1:44 pm | 6 Comments

P3PC is a project to review the performance of 3rd party content such as ads, widgets, and analytics. You can see all the reviews and stats on the P3PC home page. This blog post looks at Google AdSense. Here are the summary stats:

impact on page Page Speed YSlow doc.
write
total reqs total xfer size JS ungzip DOM elems median Δ load time
big 87 84 y 8 41 kB 76 kB 9 222 ms
column definitions
Click here to see how your browser performs compared to the median load time shown above.

After signing up for Google AdSense, you can setup different types of ads. I chose “AdSense for Content” (listed first). Here’s what an example ad looks like. (This is a static image. Go to the Compare page to see the snippet live.)

Snippet Code

Let’s look at the actual snippet code:

1: <script type=”text/javascript”><!–
2: google_ad_client = “pub-0478442537074871”;
3: /* 300×250, created 3/6/10 */
4: google_ad_slot = “4427977761”;
5: google_ad_width = 300;
6: google_ad_height = 250;
7: //–>
8: </script>
9: <script type=”text/javascript”
10: src=”http://pagead2.googlesyndication.com/pagead/show_ads.js”>
11: </script>
snippet code as of March 10, 2010

A quick walk through the snippet code:

  • lines 2-6 – Define global variables that are used by the show_ads.js script.
  • lines 9-11 – Load the show_ads.js script.

Performance Analysis

This HTTP waterfall chart was generated by WebPagetest.org using IE 7 with a 1.5Mbps connection from Dulles, VA. It reveals a lot of idiosyncrasies with scripts, browsers, and HTTP. Let’s step through each request.

  • item 1: compare.php – The HTML document.
  • item 2: show_ads.js – The main script. All other downloads are blocked because this is loaded using the SCRIPT SRC HTML tag.
  • items 3-5 – Other scripts that are loaded dynamically by show_ads.js. This dynamic loading is done by using document.write. Using document.write causes the scripts themselves to be downloaded in parallel in IE (as evidenced by the waterfall chart). However, subsequent resources are still blocked (item 7).
  • item 6: ads – The actual ad content from doubleclick.net. Google AdSense creates an iframe to hold the ad, so this is the HTML document contained in that iframe.
  • item 7: *-waterfall.png – The waterfall image in this page. This is the main content of the page. Notice how it’s blocked by the previous four scripts.
  • item 8-9: abg-en-100c-0000000.png – The “Ads by Google” image. This is loaded twice in IE because it’s referenced twice in the ad: as an IMG and as part of AlphaImageLoader.
  • item 10: sma8.js – A script loaded by the ad. Because the ad is in an iframe, this script won’t block any resources in the main page.

Now that we have a handle on the HTTP requests involved, let’s look at the most important performance issues along with recommended solutions.

1. The scripts block the main content of the page from loading.

It would be better to load the scripts without blocking. This isn’t possible with the current implementation because the ad is inserted using document.write. Calling document.write from scripts loaded asynchronously may lead to ads being inserted in the wrong location or potentially the entire page being blank. The ideal solution would be create a DIV with the desired width and height to hold the ad and load the scripts asynchronously, similar to what BuySellAds.com does.

2. Most of the resources are only cacheable for a day.

It’s understandable that show_ads.js is only cacheable for a day. If this script changed (bug fix, new feature), there would be no way to rev the filename (since the snippet is embedded in the publishers’ pages). A short expiration date ensures users will get the updated version sooner (within a day). However, expansion_embed.js, abg-en-100c-000000.png, and sma8.js are also only cacheable for a day. These should have a far future expiration date (a year or more). If there was a change to expansion_embed.js (for example), the new version could be pushed with a modified filename (expansion_embed.1.1.js) and the code in show_ads.js could be modified to reference this new filename.

3. abg-en-100c-000000.png is downloaded twice.

This is happening because an AlphaImageLoader filter is used to achieve alpha transparency in IE 6. The HTML looks like this:

1: <span style=”display:inline-block;height:16px;width:78;
2:     pxfilter:progid:DXImageTransform.Microsoft.AlphaImageLoader(
3:     src=’http://…/abg-en-100c-000000.png’);”>
4: <img src=http://…/abg-en-100c-000000.png
5:     alt=”Ads by Google” border=0 height=16 width=78
6:     style=filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0)>
7: </span>

Notice that abg-en-100c-000000.png is used in the src in both lines 3 and 4. I’m not sure why the IMG is being used with an opacity of 0 (preserve space?), but I bet there’s a workaround. Also, this should only be necessary in IE 6, so the AlphaImageLoader should be skipped for IE 7&8.

4. Five scripts are downloaded.

Some of the scripts could be combined to reduce the number of HTTP requests.


6 Comments

P3PC: Quantcast

March 23, 2010 5:57 pm | Comments Off on P3PC: Quantcast

P3PC is a project to review the performance of 3rd party content such as ads, widgets, and analytics. You can see all the reviews and stats on the P3PC home page. This blog post looks at Quantcast. Here are the summary stats:

impact on page Page Speed YSlow doc.
write
total reqs total xfer size JS ungzip DOM elems median Δ load time
small 93 98 n 2 3 kB 3 kB 2 53 ms
column definitions
Click here to see how your browser performs compared to the median load time shown above.

Quantcast does web analytics. They go beyond the typical traffic stats providing information about user demographics for advertisers. It was easy to signup for Quantcast and embed their snippet. Go to the Compare page to see the snippet in action.

Snippet Code

Let’s look at the actual snippet code:

1: <!– Start Quantcast tag –>
2: <script type=”text/javascript”>
3: _qoptions={
4: qacct:”p-d0TvozDaU_91o”
5: };
6: </script>
7: <script type=”text/javascript” src=”http://edge.quantserve.com/quant.js”></script>
8: <noscript>
9: <img src=”http://pixel.quantserve.com/pixel/p-d0TvozDaU_91o.gif” style=”display: none;” border=”0″ height=”1″ width=”1″ alt=”Quantcast”/>
10: </noscript>
11: <!– End Quantcast tag –>
snippet code as of March 22, 2010

A quick walk through the snippet code:

  • lines 3-4 – Define some variables used by the script.
  • line 7 – Load the quant.js script.
  • lines 8-10 – Provide a NOSCRIPT block that loads an image beacon using HTML.

Performance Analysis

This HTTP waterfall chart was generated by WebPagetest.org using IE 7 with a 1.5Mbps connection from Dulles, VA. Let’s step through each request.

  • item 1: compare.php – The HTML document.
  • item 2: quant.js – The main Quantcast script. This is loaded using normal SCRIPT SRC HTML tags, so it blocks subsequent resources in IE7 and older browsers, but not in newer browsers.
  • item 3: pixel.quantserve.com/pixel.gif – A beacon back to Quantcast.
  • item 4: *-waterfall.png – The waterfall image in this page. This is the main content of the page. Notice how it’s blocked by quant.js in IE7.

The Quantcast snippet is fairly performant. The few things worth noting are:

1. The quant.js script blocks resources and rendering.

The quant.js script is loaded using normal SCRIPT SRC HTML tags. Newer browsers (IE 8, Firefox 3.6, Safari 4, Chrome 2+) download this in parallel with subsequent resources. But in IE 6&7 and Opera all subsequent resources are blocked until quant.js is done downloading, as shown in the waterfall chart. In all browsers, all DOM elements below the SCRIPT tag are blocked from rendering and all JavaScript is blocked from executing. Since nothing else in the page depends on quant.js, it would be better to load it asynchronously, as is done with Google Analytics’ async snippet.

2. quant.js is only cacheable for one day.

This is the script that publishers add to their pages. As such, it has to have a short expiration time so that the end users will update their cache somewhat frequently to get bug fixes and other updates. However, one day might be too aggressive. As a point of comparison, Google Analytics’ ga.js is cacheable for one week.

3. The beacon returns a 200 HTTP status code.

I recommend returning a 204 (No Content) status code for beacons. A 204 response has no body and browsers will never cache them, which is exactly what we want from a beacon. In this case, the image body is less than 100 bytes, and the beacon’s HTTP headers prevent it from being cached. Although the savings are minimal, using a 204 response for beacons is a good best practice. Quantcast’s NOSCRIPT beacon, on the other hand, should return a 200 status code to avoid the browser thinking there’s an error.

Overall, Quantcast has a small impact on page performance. The most important improvement would be to load quant.js asynchronously.

Other posts in the P3PC series:


Comments Off on P3PC: Quantcast

P3PC: BuySellAds.com

March 16, 2010 7:09 am | 4 Comments

P3PC is a project to review the performance of 3rd party content such as ads, widgets, and analytics. You can see all the reviews and stats on the P3PC home page. This blog post looks at BuySellAds.com. Here are the summary stats:

impact on page Page Speed YSlow doc.
write
total reqs total xfer size JS ungzip DOM elems median Δ load time
small 81 92 n 3 7 kB 14 kB 9 28 ms
column definitions
Click here to see how your browser performs compared to the median load time shown above.

After signing up for BuySellAds.com, you can setup different types of ads. I chose an image-only 125×125 ad. Since this is a test page, I can’t get real ads. Check out Webdesigner Depot or All Things Cupcake to see some real ads. The folks at BuySellAds.com set me up with a test ad for demo purposes. Here’s what the test ad looks like. (This is a static image. Go to the Compare page to see the snippet live.)

Snippet Code

Let’s look at the actual snippet code:

1: <!– BuySellAds.com Ad Code –>
2: <script type=”text/javascript”>
3:     (function(){
4:         var bsa = document.createElement(‘script’);
5:         bsa.type = ‘text/javascript’;
6:         bsa.async = true;
7:         bsa.src = ‘//s3.buysellads.com/ac/bsa.js’;
8:         (document.getElementsByTagName(‘head’)[0] || document.getElementsByTagName(‘body’)[0]).appendChild(bsa);
9:     })();
10: </script>
11: <!– END BuySellAds.com Ad Code –>
12: <!– BuySellAds.com Zone Code –>
13: <div id=”bsap_1245700″ class=”bsarocks bsap_84a5f8f4c8e4c1bb2c57948fba2d9cc4″></div>
14: <!– END BuySellAds.com Zone Code –>
snippet code as of March 14, 2010

A quick walk through the snippet code:

  • lines 3-9 – Dynamically load the bsa.js script.
  • line 13 – Create a DIV to hold the ad.

Performance Analysis

This HTTP waterfall chart was generated by WebPagetest.org using IE 7 with a 1.5Mbps connection from Dulles, VA. Let’s step through each request.

  • item 1: compare.php – The HTML document.
  • item 2: bsa.js – The main script. This is loaded dynamically, so it doesn’t block other downloads.
  • item 3: *-waterfall.png – The waterfall image in this page. This is the main content of the page. Notice how it loads in parallel with bsa.js.
  • item 4: s_84a5f8f4c8e4c1bb2c57948fba2d9cc4.js – A JSON response containing the ad content. This resource was added dynamically by bsa.js.
  • item 6: 18446-1268342919.png – The image contained in the test ad.
  • item 7: imp.gif – A beacon.

The amazing thing about the BuySellAds.com snippet is that it loads ads asynchronously. Most web developers are familiar with the performance delays inflicted by ads with scripts that block the main content in the page, or even worse scripts that use document.write so any hope of parallelization is dashed. BuySellAds.com is the only ad snippet that I’ve seen that avoids these blocking issues. (If you know of others, please add a comment mentioning them.)

Asynchronous loading is achieved as a result of two things:

  1. dynamically loading bsa.js (as opposed to using normal SCRIPT SRC HTML tags)
  2. creating a DIV placeholder for the ad content (as opposed to using document.write)

How is the ad actually loaded into the DIV? The bsa.js script dynamically adds a script (s_84a5f8f4c8e4c1bb2c57948fba2d9cc4.js) containing the ad as a JSON response. That JSON response calls a function from bsa.js (interpret_json) that extracts the DIV’s id from the JSON object and sets its innerHTML. I like how the DIV’s id and classname are used, as opposed to doing this through JavaScript variables set in the snippet.

Loading ads asynchronously is a big advantage of BuySellAds.com. But there are still a few more performance improvements that could be made.

1. The size of the DIV changes causing the page to re-layout.

I used WebPagetest.org to create a filmstrip of images showing the page loading. Notice how the waterfall chart appears at 1.5 seconds. At 2.0 seconds the ad is loaded causing the waterfall chart to shift downward. It would better if the snippet set the DIV’s width and height to the appropriate values for the selected ad size.

2. bsa.js isn’t cached.

This is the script that publishers add to their pages. As such, it has to have a short expiration time so that the file cached by users is updated frequently. However, no expiration date causes browsers to check for updates too frequently. A 1 day or 1 week expiration date would strike a better balance between performance and update frequency.

3. The beacon returns a 200 HTTP status code.

I recommend returning a 204 (No Content) status code. A 204 response has no body and browsers will never cache them, which is exactly what we want from a beacon. In this case, the image body is less than 100 bytes, and the beacon’s HTTP headers prevent it from being cached. Although the savings are minimal, using a 204 response for beacons is a good best practice.

Hats off to the folks at BuySellAds.com for showing that asynchronous ads are possible. I’ll examine a few more ad snippets in the coming weeks. We’ll see how they stack up when it comes to performance.

Other posts in the P3PC series:


4 Comments

Velocity OLC, upcoming events

March 8, 2010 8:46 pm | 5 Comments

Velocity is the O’Reilly conference Jesse Robbins and I co-chair. This is our third year and it’ll be bigger and better than ever. Dates are June 22-24. We’re almost done reviewing proposals and the speaker line-up so far looks great: mobile, browsers, tools, JavaScript, metrics, and more all covered from a performance perspective. I hope you’ll be able to make it.

As a warm up to Velocity in June, O’Reilly had the great idea of starting Velocity OLC (OnLine Conference). We had the first one on December 8 with great speakers including Mike Belshe (Chrome, SPDY), Charles Jolley (SproutCore), and J Chris Anderson (CouchDB). The next Velocity OLC is coming up fast – March 17 9-11:15am (PST). The agenda is:

  • Site Performance in Google Webmaster Tools – Sreeram Ramachandran (Google)
  • MySQL Abuse – Kellan Elliott-McCrea (Flickr)
  • Keeping Track of Your Performance Using Show Slow – Sergey Chernyshev (truTV)
  • Provisioning Toolchain – Lee Thompson (DTO Solutions)
  • Diagnose and Prevent JavaScript/AJAX Performance Issues in Internet Explorer – Andreas Grabner (dynaTrace Software)

The event is free! I invited the performance speakers, Sreeram, Sergey, and Andi, because they’ve released these amazing, free tools that all web developers focused on performance should know about. I hope you’ll tune in.

I also want to mention my next few speaking appearances.

JSConf.US (April 17&18, DC) – I missed the first two years of this conference and was bummed. I heard so many good things about it, I jumped at the chance to speak at JSConf.EU last November in Berlin and it exceeded my high expectations. Now I get to experience the main event. And I’ll be back in my old (20 years ago) stomping grounds!

Web 2.0 Expo San Francisco (May 3-6) – This event is sentimental for me. 4 years ago Tenni Theurer and I showed up to do a workshop on Sunday. It was beautiful outside and we figured everyone would be out sightseeing. Instead, 300+ people showed up. That was the first conference I had spoken at in a decade, and was the beginning of the evangelism campaign that I carry on today. I’ve spoken here every year and it’s always a great, smart crowd. Super hallway discussions.

@media (London, June 8-11) – Dion and Ben turned me on to Web Directions, speaking highly of all the conferences they run. I reached out to John Allsopp and he was kind enough to put me on the speaker list. I’m pysched to see some of the speakers I know well, plus some I’ve never met. And it’s a great opportunity for me to touch base with EU web devs focused on performance. Use the “SOUDERS” discount code.

Definitely grab me if you’re at any of these events. I want to know about your biggest performance bottleneck, and tips & tricks you’d like to share. And I’m always happy to sit down with a packet sniffer and do some performance analysis on the fly.

5 Comments

WebPagetest.org – top tool

March 5, 2010 8:04 am | 12 Comments

I’m loving WebPagetest.org. In Even Faster Web Sites I said, “[WebPagetest] hasn’t gotten the wide adoption it deserves.” It got a boost after Matt Cutts mentioned WebPageTest.org in his interview with WebProNews. But I still meet people who aren’t aware that this great performance tool is out there, so let me bang their drum some more.

Pat Meenan and Eric Goldsmith are the team behind AOL Pagetest and WebPagetest.org. AOL Pagetest is the Windows tool that works in IE. Pat took that and put it behind a web server running in his basement and called it WebPagetest. That was two years ago. He took the Open Source route and now there are instances of WebPagetest running in Virginia, California, UK, China, and New Zealand hosted by AOL as well as Strangeloop Networks, Aptimize, and Daemon Solutions.

The power of WebPagetest.org is that it’s web-based – you don’t have to do any installs and you can run it on any OS and browser. On the backend, WebPagetest runs the page in either IE7 or IE8 and displays the results. This might be a limitation for some folks – if you want to test a page on Mac OS X using Safari you’ll have to do that with some other tool. But the fact that IE 7&8 are the dominate browsers means you can see the most typical experience regardless of what platform you’re currently working on. Since many developers work on Mac using Safari or Firefox, and more are moving to Chrome, it’s important that they can easily see how their web pages load for a majority of their users.

New Test

Here’s how it works: Go to the New Test tab. Enter the URL you want to test and click submit. Pretty easy! 90% of the time that’s what I do, but there are other options you can tweak:

  • pick a geo location – VA, CA, UK, CN, or NZ
  • choose IE7 or IE8
  • choose a connection speed – Dial, DSL, FIOS (Dial and DSL are done via throttling)
  • test just the first (empty cache) page load or first and repeat
  • repeat the test up to 10 times to get a bigger sample size
  • opt to keep your test results private if desired

Results

The results page shows summary stats (page load times, bytes downloaded, # of HTTP requests) and a mini performance analysis (compression, image optimization, concatenating scripts and stylesheets). But the piece I love is the waterfall chart.

If you click on the mini waterfall, it takes you to a larger view where you can do additional customizations. I’ve been relying on this for my current series of blog posts on P3PC (performance of 3rd party content). And Pat even added a few options I requested. You can set the size of the image, remove certain requests (for example, I sometimes remove favicon.ico), and whether to show the extra bits on CPU and bandwidth utilization. I end up with clean waterfall charts like this:

And there’s more – Video!

When you create a new test, you can opt to record a video of the page loading (go to the Video tab under “Step 4 – Test Options” in the figure above). WebPagetest generates a filmstrip of images as well as a video. The image filmstrip shows what the page looks like as it loads. You can choose different time increments (0.1, 0.5, 1 and 5 seconds). Wikipedia is pretty straightforward as it loads. Here’s the filmstrip for FOX Sports. Content arrives in the 0-5 second range, more images (like the logo) are filled in from 5-10 seconds, and flash arrives by the 15 second mark. You can also view the video.

Pat does a lot of this work on his own time and all the video features are in Alpha, so be tolerant. I use WebPagetest.org daily and it has become one of my favorite performance tools. Definitely give it a try.

12 Comments

P3PC: Google Analytics

March 3, 2010 7:25 pm | 16 Comments

P3PC is a project to review the performance of 3rd party content such as ads, widgets, and analytics. You can see all the reviews and stats on the P3PC home page. This blog post looks at Google Analytics. Here are the summary stats:

impact on page Page Speed YSlow doc.
write
total reqs total xfer size JS ungzip DOM elems median Δ load time
small 91 99 n 2 18 kB 24 kB 2 19 ms
column definitions
Click here to see how your browser performs compared to the median load time shown above.

Google Analytics recently had a nice performance upgrade. The old snippet used document.write and thus blocked other resources and rendering, making pages feel slower. On Dec 1, 2009, Google announced the launch of their new asynchronous snippet. The old snippet still works, but sites that want a significant speedup should use the new async snippet.

My analysis focuses on the new async snippet for Google Analytics.

Snippet Code

Let’s look at the actual snippet code:

1: <script type=”text/javascript”>
2: var _gaq = _gaq || [];
3: _gaq.push([‘_setAccount’, ‘UA-15026169-1’]);
4: _gaq.push([‘_trackPageview’]);
5:
6: (function() {
7: var ga = document.createElement(‘script’); ga.type = ‘text/javascript’; ga.async = true;
8: ga.src = (‘https:’ == document.location.protocol ? ‘https://ssl’ : ‘http://www’) + ‘.google-analytics.com/ga.js’;
9: (document.getElementsByTagName(‘head’)[0] || document.getElementsByTagName(‘body’)[0]).appendChild(ga);
10: })();
11: </script>
snippet code as of March 3, 2010

A quick walk through the snippet code:

  • lines 2-4 – Push commands onto a queue to be executed once the async script finishes loading.
  • lines 6-10 – Create a script DOM element and set the src to fetch ga.js.

Performance Analysis

This HTTP waterfall chart was generated by WebPagetest.org using IE 7 with a 1.5Mbps connection from Dulles, VA. Notice how the image in the main page (google-analytics-waterfall.png) is not blocked by ga.js – they both download in parallel.

Here are the most important performance issues along with recommended solutions.

1. 24 kB seems like a lot of JavaScript for sending a tracking beacon.

My example is very straightforward and doesn’t use much Google Analytics functionality. The three sites I run that use Google Analytics are all simple. I’d like to see a “lite” version of ga.js for sites like mine and whittle that 24 kB down to 5 kB or so.

2. The beacon returns a 200 HTTP status code.

I recommend returning a 204 (No Content) status code. A 204 response has no body and browsers will never cache them, which is exactly what we want from a beacon. In this case, no body only saves 35 bytes, and the beacon’s HTTP headers prevent it from being cached. Although the savings are minimal, using a 204 response for beacons is a good best practice.

What you can do now: The new async version of the Google Analytics snippet is pretty slim. Even YSlow and Page Speed can’t find much wrong with it. My main advice would be to switch over to this async version if you’re still using the old document.write snippet. Cruising through the Alexa U.S. top 50 web sites I found two web sites that use the new async snippet: Huffington Post and Answers.com. But these web sites haven’t moved over yet: Twitter, FOXNews.com, Reference.com, Photobucket, Hulu, DoubleClick.com, and (ahem) Blogger. To be fair, the new snippet was launched as Beta just a few months ago, but all of these sites should switchover to the async snippet and speed things up for their users.


16 Comments

P3PC: Facebook Share

March 1, 2010 8:35 pm | 1 Comment

P3PC is a project to review the performance of 3rd party content such as ads, widgets, and analytics. You can see all the reviews and stats on the P3PC home page. This blog post looks at Facebook Share. Here are the summary stats:

impact on page Page Speed YSlow doc.
write
total reqs total xfer size JS ungzip DOM elems median Δ load time
small 90 92 n 5 8 kB 7 kB 15 104 ms
column definitions
Click here to see how your browser performs compared to the median load time shown above.

Facebook Share is a way to share a URL with the Facebook community. Here’s what it looks like. (This is a static image. Go to the Compare page to see the live widget.)

Snippet Code

Let’s look at the actual snippet code:

1: <a name=”fb_share” type=”button_count” share_url=”https://stevesouders.com/” href=”http://www.facebook.com/sharer.php”>Share</a>
2: <script src=”http://static.ak.fbcdn.net/connect.php/js/FB.Share” type=”text/javascript”></script>
snippet code as of March 1, 2010

A quick walk through the snippet code:

  • line 1 – The anchor that will be filled in later.
  • line 2 – The FB.Share script is downloaded. The actual code is minified, but I’ve expanded some of it here for easier readability. The _onFirst function is called (line 1 below). _onFirst inserts the share-button-css stylesheet (lines 2-6) and then calls renderPass. renderPass calls fetchData which inserts the restserver.php script (lines 12-14). The insert function appends the DOM element (stylesheet or script) to the head or body of the document (line 19).
    1: _onFirst: function() {
    2: var a=document.createElement(‘link’);
    3: a.rel=’stylesheet’;
    4: a.type=’text/css’;
    5: a.href=’http://static.ak.fbcdn.net/connect.php/css/share-button-css’;
    6: this.insert(a);
    7: renderPass();
    8: […]
    9: },
    10:
    11: fetchData: function() {
    12: var a=document.createElement(‘script’);
    13: a.src=this.addQS(‘http://api.ak.facebook.com/restserver.php’, {v:’1.0′,method:[…]});
    14: this.insert(a);
    15: […]
    16: },
    17:
    18: insert: function(a) {
    19: (document.getElementsByTagName(‘HEAD’)[0]||document.body).appendChild(a);
    20: },

Performance Analysis

This HTTP waterfall chart was generated by WebPagetest.org using IE 7 with a 1.5Mbps connection from Dulles, VA. Item 5 (facebook-sharer-waterfall.png) is the first resource that’s part of the main page. Notice how it’s blocked by the first Facebook Share script, but then loads in parallel with the widget’s stylesheet and second script.

Here are the most important performance issues along with recommended solutions.

1. The FB.Share script blocks resources and rendering.

It’s great that the stylesheet (share-button-css) and second script (restserver.php) are loading dynamically and don’t block the main page’s resources (facebook-sharer-waterfall.png). But the first script (FB.Share) is loaded with the typical SCRIPT SRC tags and so does block in older browsers, and even in newer browsers will have some blocking effects. Because there are no code dependencies and no use of document.write (yay!), the FB.Share script can also be loaded asynchronously. Here’s what the async snippet might look like. (Warning: I haven’t tested this on all browsers.)

1: <a name=”fb_share” type=”button_count” share_url=”https://stevesouders.com/” href=”http://www.facebook.com/sharer.php”>Share</a>
2: <script type=”text/javascript”>
3: (function() {
4: var domscript = document.createElement(“script”);
5: domscript.type = “text/javascript”;
6: domscript.src = “http://static.ak.fbcdn.net/connect.php/js/FB.Share”;
7: (document.getElementsByTagName(“head”)[0] || document.getElementsByTagName(“body”)[0]).appendChild(domscript);
8: }());
9: </script>

This async snippet is used in the Facebook Sharer Improved example. The HTTP waterfall chart for this async snippet is shown below. The most important thing about loading the FB.Share script asynchronously is that the main page’s content can load more quickly. Notice how the image in the main page (facebook-sharer-waterfall.png) moves from item 5 to item 3, and its load time moves from ~1100 ms to ~780 ms. Another benefit is that the overall page load time is faster, dropping from ~1100 ms to ~900 ms.

2. share-button-css is only cached for a few minutes

share-button-css should be given a far future expiration date. If it’s changed, the filename could be modified in FB.Share guaranteeing that everyone got the updated file.

3. The CSS could be reduced.

Page Speed reports that 50% (2.9 kB) of the CSS isn’t used. It’s possible the CSS is used in other manifestations of the widget but not in this default view.

What you can do now: Facebook Share is a lightweight widget as widgets go. In addition to a small transfer size and small amount of JavaScript, its images and CSS selectors are also optimized. But if you wanted to reduce the impact even farther, you could try loading FB.Share asynchronously.


1 Comment

P3PC: Digg Widget

February 28, 2010 1:33 pm | 10 Comments

Update: In March, 2010 Digg revamped their snippet to have much better performance. See their blog post Speeding Along

P3PC is a project to review the performance of 3rd party content such as ads, widgets, and analytics. This blog post looks at the Digg Widget. Here are the summary stats:

impact on page Page Speed YSlow doc.
write
total reqs total xfer size JS ungzip DOM elems median Δ load time
big 90 84 y 9 52 kB 107 kB 84 667 ms
column definitions
Click here to see how your browser performs compared to the median load time shown above.

The Add a Digg Widget page describes how to insert this widget into a page. Here’s what it looks like:

Snippet Code

Let’s look at the actual snippet code:

1: <script type=”text/javascript”>
2: digg_id = ‘digg-widget-container’; //make this id unique for each widget you put on a single page.
3: digg_title = ‘Top 10 list from Technology’;
4: </script>
5: <script type=”text/javascript” src=”http://digg.com/tools/widgetjs”></script>
6: <script type=”text/javascript” src=”http://digg.com/tools/services?type=javascript&amp;callback=diggwb&amp;endPoint=%2Fstories%2Fcontainer%2Ftechnology%2Ftop&amp;count=10″></script>
snippet code as of Feb 23, 2010

A quick walk through the snippet code:

  • lines 1-4 – Variables used later in the loaded scripts.
  • line 5 – The “widgetjs” script is where most of the action takes place.
    This script uses document.write to load a stylesheet and two more scripts:

    1: document.write(‘<link rel=”stylesheet” type=”text/css” media=”all” href=”http://digg.com/css/widget.css” />’);
    2: document.write(‘<script type=”text/javascript” src=”http://cotnet.diggstatic.com/js/loader/380/JS_Libraries,jquery|JS_Libraries,jquery-noconflict|jquery-dom”></script>’);
    3: document.write(‘<script type=”text/javascript” src=”http://digg.com/tools/widgetjsvars”></script>’);

    The “widgetjsvars” script does several document.writes including loading another script:

    1: document.write(‘[…]<script src=”http://cotnet.diggstatic.com/js/loader/395/omnidiggthis” type=”text/javascript”></script>’);
  • line 6 – The “/tools/services” script contains the data (stories) for the widget.

Performance Analysis

This HTTP waterfall chart was generated by WebPagetest.org using IE 7 with a 1.5Mbps connection from Dulles, VA. Item 10 (digg-waterfall.png) is the first resource that’s part of the main page. Notice how it’s blocked by the Digg widget’s scripts.

Here are the most important performance issues along with recommended solutions.

  1. 9 HTTP requests, 52 kB transferred over the wire, and 107 kB of JavaScript (uncompressed) is a lot of content for a single widget.
    Recommendations:

    • Concatenate these three scripts: JS_Libraries, widgetjsvars, and omnidiggthis. (eliminates 2 HTTP requests)
    • Run Page Speed’s “Defer loading JavaScript” feature and see how much of the JavaScript is not used. If it’s sizable, delete it. (This feature is currently broken in the latest version of Page Speed, but a fix is imminent.) (eliminates ?? kB)
    • Optimize the images – widget-logo.png and get-widget.png can both be reduced by ~3 kB. (eliminates ~6 kB)
    • Sprite widget-logo.png and shade-com.png. (eliminates 1 HTTP request)
  2. The widget’s scripts block the main page’s content from downloading. Looking at the waterfall chart, the main page includes the image “digg-waterfall.png” (row 10). Notice how this image doesn’t start downloading until after all the scripts for the Digg widget are received.
    Recommendations:

    • Instead of loading the scripts using document.write, load them without blocking other downloads. The scripts are already suffering from race condition behavior, as evidenced by this comment from widgetjsvars:
      1: if (!digg || !digg.$) setTimeout(function() { diggwb(obj); }, 200); //hack for IE not loading scripts that are included via document.write until it decides too

    So it probably isn’t too much work to avoid race conditions when making all the scripts load asynchronously.

  3. The widget’s stylesheet blocks the main page from rendering in IE.
    Recommendations:

    • Instead of loading the stylesheet using document.write, load it via JavaScript as described in 5d dynamic stylesheets.
  4. Four of the resources aren’t cached long enough.
    Recommendations:

    • Two scripts aren’t cacheable because they have an expiration date in the past. widgetjs is part of the snippet, so it can’t have a long expiration date, but something like an hour or a day would be better than a date in the past. widgetjsvars could have a far future expiration date since its URL is specified in widgetjs.
    • The three images are only cacheable for a day. They should have a far future expires header since the image filename can be change if it’s modified.
  5. There are approximately 30 inefficient CSS selectors. Because this stylesheet is part of the main page, the selectors will cause the overall page to render more slowly when these selectors are applied to the elements in the main page.
    Recommendations:

  6. Four of the resources have ETags which reduces their cacheability.
    Recommendations:

    • Configure the ETags for widget.css, widget-logo.png, get-widget.png, and shade-com.png.

What you can do now: Because the Digg Widget uses document.write, the best thing you can do to reduce the impact it has on your page is to put it in an iframe. This will remove the blocking effect it has on your page.


10 Comments