Web Performance Best Practices: How masters.com re-designed their site to boost performance – and what that re-design missed

Last week I blogged about the 6 Steps to identify the major web site performance problems on sites like masters.com. Unfortunately for me I did the analysis 3 days before they re-launched their website. The site looks really nice now – great job.
They fixed some of the problems I highlighted in the blog and also follow more of the best practices outlined by Google and Yahoo. In order to give them credit for the work they put in I ran another analysis on the new site. It should be interesting for everybody to see what they have changed, what they haven’t changed, what new problems they introduced and how this all impacts the web site performance to the end user.

Merging files to speed up resource loading?

On the old site the initial page loaded 23 JavaScript files and 99 images. This is now down to 2 JavaScript and 13 images. Sounds like a great improvement – but let’s have a closer look:
First of all it is a bit hard to compare two individual pages because the web site changed in terms of its structure. The first page on the old site showed different content than on the new site. Overall there are however definitely fewer images. There are even more options to bring this number down by using CSS Sprites.
The interesting part is JavaScript. A general best practice is to merge JavaScript files into fewer files. This practice was kind of followed – but only kind of: Instead of merging the code into fewer JavaScript files, the code of all required JavaScript libraries on each page was embedded in the HTML document. This approach definitely limits the number of roundtrips to download the code but it has one huge drawback: Caching these files is not possible as they are embedded in dynamically-generated HTML. The following screenshot shows the 8 individual html documents (pages) I requested. Each of these pages includes all JavaScript libraries which make up about 95% of the total document size:

Each HTML Document contains all JavaScript code embedded which contributes to ~95% of Document Size
Each HTML Document contains all JavaScript code embedded which contributes to ~95% of Document Size

In my scenario of the 8 pages I have a total of 2.6MB in HTML document size. This size can be reduced to aprox. 130kb when extracting the embedded JavaScript code into a single JavaScript file. This single JavaScript file would be ~300kb in size and must only be requested once by the client as it can easily be cached in the local browser cache. The JavaScript code itself can also be optimized. Most of the code can be minimized and obfuscated. Some of the libraries also get loaded via a technique described in Faster Loading through eval(). While loading the actual JavaScript might be faster – executing it is much slower. For a detailed analysis on this, check out Step 6: Optimizing JavaScript execution and load performance my previous blog.

The big problem I see here – even though they managed to avoid many roundtrips – is that every user must download ~300kb of HTML for every page request. In times of high-speed internet this might not seem like a problem but a) not everybody has this kind of internet speed and b) their servers are pounded with additional load and network bandwidth to the servers might become a problem with increasing load.

Expensive and too many redirects

I often enter web site Url’s without the www in the beginning, e.g.: masters.com instead of www.masters.com. Websites usually redirect me to the correct page and I save 3 letters to type :-). Redirects like this are additional network roundtrips which we basically want to avoid in order to speed up the site. Looking at the network activity I can not only see that the initial redirect takes a very long time (4s in my case), it redirects me to another redirect adding another 570ms before I finally end up on the index.html page. The following image shows the 3 network requests when entering the URL without the www domain prefix:

Expensive redirects to get from masters.com to www.masters.com/index.html
Expensive redirects to get from masters.com to www.masters.com/index.html

What exactly does the network activity tell us in this case?

  • Initial request takes 4.2 seconds (including DNS lookup, Connect- and Server-Time) and redirects me to www.masters.com. The fact that I am in Europe right now probably contributes a bit to the 4.2 seconds as I assume that the web-server sits somewhere in the US.
  • The 2nd request to www.masters.com redirects me to www.masters.com/index.html and takes 570ms in total. This redirect could really be avoided by redirecting me to that page in the first place
  • The 3rd request now goes to the actual index.html page which takes 2.4s in my case. Most of the time is transfer time as I am downloading 275kb of data. Again – this time is probably faster if I would sit somewhere closer to the servers – but – as discussed in the previous section this file is so big because it contains all the JavaScript code

For some further reading check out Step 3: Can we speed up downloading all these resources? in my first blog.

IE7 bug causes wrong browser detection and fallback to IE6

When I analyze a web site I always start by looking at the Summary View for my recorded session. I saw something that made me curious:

2468 Text Resources are referenced on these pages I visited

The resource chart shows me which resources are downloaded from the web and how many are retrieved from the local browser cache. There are 2468 Text resources that were accessed from my local browser cache. This made me curious as it was definitely something you don’t see that often. A double-click on the bar in this chart brings me to the Network View showing me all these requests:

PNG Fix for IE5.5 and IE6 gets downloaded and then loaded from local cache 2468 times
PNG Fix for IE5.5 and IE6 gets downloaded and then loaded from local cache 2468 times

The single file that gets downloaded once, cached and then accessed from the cache 2468 times is an IE Html Component that provides a fix for a .png issue. This file makes sense – but only if I would run on IE6 – which I don’t. I am using IE7 and was therefore wondering why the web site downloads this file and reference it so many times. A closer look into the HTML files revealed the problem. The site does a browser check by querying the User-Agent property of the Navigator object. This is a common practice to identify the current browser version. Unfortunately there is a bug in IE7 that returns a wrong User-Agent in case the User-Agent string is longer than 256 characters. Therefore the following code gets executed for all the .png files that are on every single page causing the htc file to be loaded:

IE6 is identified due to IE7 bug and causes pngfix file to be loaded
IE6 is identified due to IE7 bug and causes pngfix file to be loaded

Caching files too short

Caching files in the local browser cache is a good thing. Resources that hardly ever change can be cached locally and the browser doesn’t need to request these files every time the user visits the page. As outlined in my first analysis in Step 4: How good is my 2nd visit experience? it is important to use the correct cache control settings. It seems that the re-launched site still has the same problem as the old one. Images have a cache setting of only a couple of minutes. The following screenshot shows the network requests of a 2nd visit to their page after I did my first walkthrough about 15 minutes ago:

Very short cache setting causes browser to check server for newer versions of these images
Very short cache setting causes browser to check server for newer versions of these images

I recorded this session on April 2nd 2010, 19:27 GMT. The Expires header is set to ~13 minutes only. Looking at these images I doubt that they will change that frequently. The problem here is that the browser needs to send a request for all these images. Even though the response just says “NOT MODIFIED SINCE” – we have many roundtrips that can all be avoided. Do the math and build the sum of the Total column in the screenshot above – this is the time that can be saved with correct cache settings.
To solve this problem it is recommended to use far-future expires headers. Check out the RFC for Cache Control as well as the Best Practices on this topic by Yahoo and Google. Unless there is a reason to constantly download these files (in case they really frequently change) it is better to leverage the local browser cache and reduce download times.

Optimizing JavaScript and DOM Access

The final analysis step is looking at JavaScript execution. Overall I have to say that the page is really good in terms of JavaScript execution time. But there are always things that can be improved. I found two things that can easily be improved and therefore save lots of time in JS execution. The first one is on the “Players” page. Data on the players is downloaded via an XHR call returning an XML document that contains a record for each player including first name, last name, country, … This XML is then processed, and JavaScript objects are created for each player. The following screenshot shows the JavaScript execution for iterating through the XML elements:

Iterative calls to $(this) for each player can be optimized
Iterative calls to $(this) for each player can be optimized

For each of the 99 players that were returned by the XHR call, the code in the each loop uses the $(this) to get a jQuery object for the current XML record. One call to this method would be enough – and would therefore save several hundred calls to this method as you can simply store it in a variable and use this variable instead.

Another common problem – and I’ve blogged about that many times – are expensive CSS Selectors. Check my recent blog about 101 on jQuery Selector Performance to get background information on this problem. The following screenshot shows me the top CSS Selectors used on masters.com:

Selectors by class name are expensive in IE and cause huge performance impacts
Selectors by class name are expensive in IE and cause huge performance impacts

Especially those selectors by class name, e.g.: “.middle703″, .”middle346”, … are very expensive as Internet Explorer doesn’t provide a native implementation to query elements by class name. Frameworks like jQuery therefore need to iterate through the whole DOM and find these elements by looking at each class name of each DOM element. Just taking the top 3 selectors on this page – which total  1.3s – show how much performance improvements is possible. By using a different way to identify those elements – e.g.: by unique ID – this time can be reduced by 90-95%. It is also questionable why the top two queries are called 32 times. I am sure we can cache the result of the first lookup and reuse it -> saves even more time.


The re-launch of this site was really well done. The page definitely feels much faster than the old one. Some of the problems I’ve highlighted in my first analysis blog of the old site have been fixed. Some are still in there and if fixed can improve performance even further. Some – like the IE7 bug issue or the large HTML documents – have been introduced and should be fixed.
With increasing number of online visitors throughout the main event, content delivery could become a serious performance problem as the servers will be bombarded with more requests than necessary. Following best practices like using a Content Deliver Network, leveraging the browsers cache, minifying content and optimizing AJAX/JavaScript execution will greatly improve web site performance and will lead to happier users. Happier users lead to more clicks and ultimately to more revenue through ads I recommend looking at the following links to learn more: Google Web Performance Best Practices, Yahoo Best Practices to Speed up your Web Site, Steve Souders Blog, How to Speed Up sites like vancouver2010.com by more than 50% in 5 minutes, How to analyze and speed up content rich web sites like www.utah.travel in minutes and Webinar with Monster.com on Best Practices to prevent AJAX/JavaScript performance problems

Andreas Grabner has 20+ years of experience as a software developer, tester and architect and is an advocate for high-performing cloud scale applications. He is a regular contributor to the DevOps community, a frequent speaker at technology conferences and regularly publishes articles on blog.dynatrace.com. You can follow him on Twitter: @grabnerandi