Google +1 Button Performance Review

UPDATE: Google released a non-blocking version of the button!
July 26: +1 for the Google engineers for fixing the button within a couple of weeks after the initial release. They have announced that the button now loads in a non-blocking way and is a lot faster. Yeah! Get the new button code here.
UPDATE: Google is working on the problems
June 7: I just received a nice email from an engineer at Google, explaining some of the choices they made and telling me they are working hard on fixing the performance problems. Stay tuned for a follow-up analysis!

On June 1 2011, Google released the +1 Button for the whole web. Being a web performance optimization consultant and knowing the Facebook Like Button and other third party widgets, ads and trackers can have a significant impact on page load time, I immediately took a look at the Google +1 Button code, created a test page and ran some first performance test.
In this article I want to share my findings with you. In short: the Google +1 Button performance is very disappointing. The extra page load time can easily be 2 seconds.

I have found 6 performance issues for the Google +1 Button as it is now.

  1. Blocking JavaScript in the <head>
  2. Redirect from HTTP to HTTPS (aka: the typo in the code generator)
  3. Browser caching for 6 minutes, proxies disallowed
  4. Serve the JS file over HTTPS
  5. Document.write for Blogger pages
  6. JS file is not minified
Read the description of each performance problem first - and especially 1,2 and 5 - and then view the code for loading the Google +1 Button in a non-blocking way.

Blocking JavaScript in the <head>

Google offers a nice and simple online code generator to create a custom Google +1 Button. You can choose language and size and use a couple of advanced options.

Here's an example of the Google +1 Button code from the generator:

<!-- Place this tag in your head or just before your close body tag -->
<script type="text/javascript" src="http://apis.google.com/js/plusone.js"></script>

<!-- Place this tag where you want the +1 button to render -->
<g:plusone></g:plusone>

The big problem with this code lies in that first comment:

<!-- Place this tag in your head or just before your close body tag -->
Google tells you that it's fine to place the script tag in the HEAD section of the HTML document. And that is bad advice. Scripts block rendering and in older browsers they also block the downloading of resources further down in the page. Tony Gentilcore explained this nicely on his blog recently: How a web page loads.
If you place the Google +1 Button script in the HEAD, it will delay the initial rendering of the page. The visitor will be staring at an empty screen longer. Bounce rate goes up, revenues and user satisfaction goes down.

You might think at this point "Google servers are fast and newer browsers parse and execute JavaScript fast, so the impact on user experience will be low". You are wrong. I created a simple test page and ran tests in IE6-9, Chrome11 and FF4 (all on Windows). Go look at the test page and all the waterfall charts and you will agree: the impact is far from low. It's big.

Here's the waterfall chart for IE8. The downloading of the image on the page is delayed by 0.5 seconds and onload is delayed by (0.5 + 0.8 =) 1.3 seconds. Google +1 Button Performance Review - IE8 empty cache - waterfall chart
View full test results on Webpagetest.org

There is no reason to put that script tag in the <head>. None.
Please Google, change that comment. Tell webmasters to put the script at the bottom of the HTML, right before the closing </body> tag. Or even better: tell them to load the JS file in a non-blocking way if they are not on Blogger.

Redirect from HTTP to HTTPS (aka: the typo in the code generator)

Yes, there is a typo in the generator's code and it's bad for performance.

<script type="text/javascript" src="http://apis.google.com/js/plusone.js"></script>
The file is called over HTTP, but will be served over HTTPS. And so, a redirect will take place. This redirect will easily take 0.2 seconds, and probably more in many cases. Many modern browsers cache redirects, so not all users will feel the pain of this. But many will, including people on IE8.
Did Google do this deliberately? Maybe, but I can't think of a good reason.

Serve the JS file over HTTPS

Fetching files over HTTPS is slower than over HTTP. Setting up the secure connection takes time, circa 200 ms each time. Scroll back up on this page and look at the waterfall chart again. The pink in the bars is the time it takes to establish the secure connection.

Why always serve the file over HTTPS? Why not re-use the protocol check part of the Google Analytics tracking code and only go HTTPS if the current page is on HTTPS?
I assume there is no sensitive information sent over the wire when loading the +1 Button or when someone uses the button on the page. But those are just assumptions. I did not actually take a close look at all the other files that get pulled in from Google servers and what info is sent to Google. Maybe there is something going on that justifies always using HTTPS. I hope there is, because caching, HTTPS and IE don't play nicely together. Read on ...

Browser caching for 6 minutes, proxies disallowed

Google offers webmasters all kinds of advice on how to make your site faster in the Page Speeds Performance Best Practices Documentation. A whole section is dedicated to optimizing caching and rightfully so. Images, CSS and JavaScript files should be aggresively cached on the client for maximum site speed. In the case of the Google +1 Button, enabling browsers to cache and re-use the files is especially important, for two reasons:

So the big question is: can browsers cache the +1 Button files and re-use them from cache, for a long time? You guessed the answer: no.

Let's take a look at the response headers that are sent with the first JavaScript file (that is the most important of all files because it blocks page rendering).

HTTP/1.1 200 OK
Content-Type: text/javascript; charset=utf-8
Expires: Fri, 03 Jun 2011 09:01:52 GMT
Date: Fri, 03 Jun 2011 09:01:52 GMT
Cache-Control: private, max-age=360
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Server: GSE
Content-Encoding: gzip
The problem is marked red. Browsers may cache the file for 6 minutes (360 / 60). Why 6 minutes? Why not 24 hours, a week or 30 days? Is it because the button has to show a recent number of +1's for that particular web page? That kinda makes sense, but surely there is a better way to accomplish that.
All the other files (CSS, JS and a sprite image) are sent with the correct, far-future Cache-control headers. You might expect that browsers only (unnecessarily) redownload that single JavaScript file after 6 minutes, right? Wrong.

This IE8 repeat view waterfall chart clearly shows that IE8 redownloads one file from each domain: Google +1 Button Performance Review - IE8 primed cache - waterfall chart More info about why IE does this can be found in Eric Law's blog post HTTPS Caching and Internet Explorer.

The Google performance documentation mentions the thing about Firefox, file caching and HTTPS: "Use the Cache control: public directive to enable HTTPS caching for Firefox."

I'd really like to know why Google always serves the files over HTTPS and sets browser caching to 6 minutes max.

Document.write for Blogger pages

In the Google +1 Button JavaScript file (https://apis.google.com/js/plusone.js) there is a function for determining if another JS file should be loaded in with 'evil' document.write:

function shouldLoadSync() {
 if(window["___gapisync"] === !0) {
  return!0
}
 for(var metas = document.getElementsByTagName("meta"), i = 0;i < metas.length;++i) {
  var meta = metas[i];
   if("generator" == meta.getAttribute("name") && "blogger" == meta.getAttribute("content")) {
	return!0
  }
}
return!1
}

Apparently, if your site runs on the Blogger platform, the other JS file cannot be dynamically appended to the DOM (aka: loaded in the preferred, good, non-blocking way). Why is that? I don't know. Fact is, if your site/blog runs on Blogger, the JS file will be loaded with document.write which blocks other downloads in Firefox 3.6. Also, in all browsers, rendering will come to a halt while that 2nd JS file is loaded, parsed and executed.

JS file is not minified

For better performance and as per one of the Google Page Speed performance best practices JavaScript code should be minified. This reduces the number of bytes and speeds up downloading, parsing and execution time.

Minifying the code of that first JS file with UglifyJS results in a 48% saving before compression.

After compression the difference is less, approximately 628 bytes (-27%): I think most people will agree with the prediction that the Google +1 Button will be very popular very soon. With many browsers not using the file from cache, Google servers will be unnecessarily sending 628 bytes over the wire many, many times every day. That is a waste of time, bandwidth, server resources and energy consumption.

Load the Google +1 Button in a non-blocking way

If your site is not running on the Blogger platform, use this code (optimized to perfection by Mathias Bynens to load the Google +1 Button. The big benefit is that page rendering is not blocked while the JS file is downloading. This works in all browsers.

<!-- Place this tag just before your close body tag -->
<script>
(function(d, t) {
var g = d.createElement(t),
	s = d.getElementsByTagName(t)[0];
g.async = true;
g.src = 'https://apis.google.com/js/plusone.js';
s.parentNode.insertBefore(g, s);
})(document, 'script');
</script>

<!-- Place this tag where you want the +1 button to render -->
<g:plusone></g:plusone>

Your feedback please!

I'm looking forward to receiving your questions and remarks.
Please, speak up!
Leave your comment below (now comment), send me a message via Twitter or via email: aaron {at} aaronpeters {dot} nl.

Like it? Share it!

Comments