the Performance Golden Rule
Yesterday I did a workshop at Google Ventures for some of their portfolio companies. I didn’t know how much performance background the audience would have, so I did an overview of everything performance-related starting with my first presentations back in 2007. It was very nostalgic. It has been years since I talked about the best practices from High Performance Web Sites. I reviewed some of those early tips, like Make Fewer HTTP Requests, Add an Expires Header, and Gzip Components.
But I needed to go back even further. Thinking back to before Velocity and WPO existed, I thought I might have to clarify why I focus mostly on frontend performance optimizations. I found my slides that explained the Performance Golden Rule:
80-90% of the end-user response time is spent on the frontend.
Start there.
There were some associated slides that showed the backend and frontend times for popular websites, but the data was old and limited, so I decided to update it. Here are the results.
First is an example waterfall showing the backend/frontend split. This waterfall is for LinkedIn. The “backend” time is the time it takes the server to get the first byte back to the client. This typically includes the bulk of backend processing: database lookups, remote web service calls, stitching together HTML, etc. The “frontend” time is everything else. This includes obvious frontend phases like executing JavaScript and rendering the page. It also includes network time for downloading all the resources referenced in the page. I include this in the frontend time because there’s a great deal web developers can do to reduce this time, such as async script loading, concatenating scripts and stylesheets, and sharding domains.
For some real world results I look at the frontend/backend split for Top 10 websites. The average frontend time is 76%, slightly lower than the 80-90% advertised in the Performance Golden Rule. But remember that these sites have highly optimized frontends, and two of them are search pages (not results) that have very few resources.
For a more typical view I looked at 10 sites ranked around 10,000. The frontend time is 92%, higher than the 76% of the Top 10 sites and even higher than the 80-90% suggested by the Performance Golden Rule.
To bring this rule home to the attendees I showed the backend and frontend times for their websites. The frontend time was 84%. This helped me get their agreement that the longest pole in the tent was frontend performance and that was the place to focus.
Afterward I realized that I have timing information in the HTTP Archive. I generally don’t show these time measurements because I think real user metrics are more accurate, but I calculated the split across all 50,000 websites that are being crawled. The frontend time is 87%.
It’s great to have this updated information that shows the Performance Golden Rule is as accurate now as it was back in 2007, and points to the motivation for focusing on frontend optimizations. If you’re worried about availability and scalability, focus on the backend. But if you’re worried about how long users are waiting for your website to load focusing on the frontend is your best bet.
jQuery 1.4 performance
JQuery 1.4 was released yesterday. I lifted the text from the release announcement, removed stop words, converted to lowercase, and found the ten most used words:
- jquery (71)
- function (27)
- performance (23)
- object (20)
- events (19)
- element (15)
- ajax (15)
- dom (13)
- json (12)
- request (10)
That’s right, “performance” comes in third ahead of “object”, “element”, and even “dom”. Anyone think jQuery 1.4 had a focus on performance? Here’s what John Resig says.
Performance Overhaul of Popular Methods
Many of the most popular and commonly used jQuery methods have seen a significant rewrite in jQuery 1.4. When analyzing the code base we found that we were able to make some significant performance gains by comparing jQuery against itself: Seeing how many internal function calls were being made and to work to reduce the complexity of the code base.
He includes this chart that shows the reduction of complexity for some popular functions.
Of course, all of this is music to my ears. There was one other specific note that caught my eye in this commit comment:
Switched from using YUI Compressor to Google Compiler. Minified and Gzipped filesize reduced to 22,839 bytes from 26,169 bytes (13% decrease in filesize).
Minifying JavaScript is one of the rules I wrote about in High Performance Web Sites. Back then (2006-2007), the best tool for minifying was JSMin from Doug Crockford. It still might be the best tool today for minifying in realtime (e.g., dynamic Ajax and JSON responses). For minifying static files, YUI Compressor (released in late 2007) does a better job. It also works on CSS. So this move from YUI Compressor to the Google Closure Compiler by John Resig, someone who obviously cares about performance, is a big deal.
For jQuery 1.4, the savings from switching to Compiler was 13%. If you have done comparisons with your code, please add your stats via a comment below.
My last blog post (Stuck inside Classic Rock) got pretty esoteric at the end when I started talking about Quality, and I promised a follow-up post on how that related to web performance. I’m still working on that post, but am happy to take this digression. But is it a digression? I’ve been talking to folks over the past week about how they strive for and compromise on quality in their jobs. We all compromise on quality to a certain degree. But occasionally, a person is afforded the opportunity to dedicate a significant portion of their life to a single-minded purpose, and can reach levels of Quality that standout in comparison. John Resig has achieved that. Congratulations to John and the jQuery team. Keep up the good (high performance) work!
Even Faster Web Sites in Skiathos
Ioannis Cherouvim, a software engineer from Greece, sent me this photo:
He took Even Faster Web Sites with him on his vacation to Skiathos, a Greek island in the Aegean Sea. In his email, Ioannis mentioned that applying the tips from my previous book to the newspaper web site Eleftherotypia (“free press” in Greek) saved “10GB traffic per day which really made a difference in our datacenter bill.” In addition, the users of the site got a better user experience.
Improved web performance and views of the Aegean Sea from the shores of a Greek island – now that’s heaven. Thanks, Ioannis – you made my day!
don’t use @import
In Chapter 5 of High Performance Web Sites, I briefly mention that @import has a negative impact on web page performance. I dug into this deeper for my talk at Web 2.0 Expo, creating several test pages and HTTP waterfall charts, all shown below. The bottomline is: use LINK instead of @import if you want stylesheets to download in parallel resulting in a faster page.
LINK vs. @import
There are two ways to include a stylesheet in your web page. You can use the LINK tag:
<link rel='stylesheet' href='a.css'>
Or you can use the @import rule:
<style> @import url('a.css'); </style>
I prefer using LINK for simplicity—you have to remember to put @import at the top of the style block or else it won’t work. It turns out that avoiding @import is better for performance, too.
@import @import
I’m going to walk through the different ways LINK and @import can be used. In these examples, there are two stylesheets: a.css and b.css. Each stylesheet is configured to take two seconds to download to make it easier to see the performance impact. The first example uses @import to pull in these two stylesheets. In this example, called @import @import, the HTML document contains the following style block:
<style> @import url('a.css'); @import url('b.css'); </style>
If you always use @import in this way, there are no performance problems, although we’ll see below it could result in JavaScript errors due to race conditions. The two stylesheets are downloaded in parallel, as shown in Figure 1. (The first tiny request is the HTML document.) The problems arise when @import is embedded in other stylesheets or is used in combination with LINK.

Figure 1. always using @import is okay
LINK @import
The LINK @import example uses LINK for a.css, and @import for b.css:
<link rel='stylesheet' type='text/css' href='a.css'> <style> @import url('b.css'); </style>
In IE (tested on 6, 7, and 8), this causes the stylesheets to be downloaded sequentially, as shown in Figure 2. Downloading resources in parallel is key to a faster page. As shown here, this behavior in IE causes the page to take a longer time to finish.

Figure 2. link mixed with @import breaks parallel downloads in IE
LINK with @import
In the LINK with @import example, a.css is inserted using LINK, and a.css has an @import rule to pull in b.css:
<link rel='stylesheet' type='text/css' href='a.css'>
@import url('b.css');
This pattern also prevents the stylesheets from loading in parallel, but this time it happens on all browsers. When we stop and think about it, we shouldn’t be too surprised. The browser has to download a.css and parse it. At that point, the browser sees the @import rule and starts to fetch b.css.

Figure 3. using @import from within a LINKed stylesheet breaks parallel downloads in all browsers
LINK blocks @import
A slight variation on the previous example with surprising results in IE: LINK is used for a.css and for a new stylesheet called proxy.css. proxy.css is configured to return immediately; it contains an @import rule for b.css.
<link rel='stylesheet' type='text/css' href='a.css'> <link rel='stylesheet' type='text/css' href='proxy.css'>
@import url('b.css');
The results of this example in IE, LINK blocks @import, are shown in Figure 4. The first request is the HTML document. The second request is a.css (two seconds). The third (tiny) request is proxy.css. The fourth request is b.css (two seconds). Surprisingly, IE won’t start downloading b.css until a.css finishes. In all other browsers, this blocking issue doesn’t occur, resulting in a faster page as shown in Figure 5.

Figure 4. LINK blocks @import embedded in other stylesheets in IE

Figure 5. LINK doesn't block @import embedded stylesheets in browsers other than IE
many @imports
The many @imports example shows that using @import in IE causes resources to be downloaded in a different order than specified. This example has six stylesheets (each takes two seconds to download) followed by a script (a four second download).
<style> @import url('a.css'); @import url('b.css'); @import url('c.css'); @import url('d.css'); @import url('e.css'); @import url('f.css'); </style> <script src='one.js' type='text/javascript'></script>
Looking at Figure 6, the longest bar is the four second script. Even though it was listed last, it gets downloaded first in IE. If the script contains code that depends on the styles applied from the stylesheets (a la getElementsByClassName, etc.), then unexpected results may occur because the script is loaded before the stylesheets, despite the developer listing it last.

Figure 6. @import causes resources to be downloaded out-of-order in IE
LINK LINK
It’s simpler and safer to use LINK to pull in stylesheets:
<link rel='stylesheet' type='text/css' href='a.css'> <link rel='stylesheet' type='text/css' href='b.css'>
Using LINK ensures that stylesheets will be downloaded in parallel across all browsers. The LINK LINK example demonstrates this, as shown in Figure 7. Using LINK also guarantees resources are downloaded in the order specified by the developer.

Figure 7. using link ensures parallel downloads across all browsers
These issues need to be addressed in IE. It’s especially bad that resources can end up getting downloaded in a different order. All browsers should implement a small lookahead when downloading stylesheets to extract any @import rules and start those downloads immediately. Until browsers make these changes, I recommend avoiding @import and instead using LINK for inserting stylesheets.
Update: April 10, 2009 1:07 PM
Based on questions from the comments, I added two more tests: LINK with @imports and Many LINKs. Each of these insert four stylesheets into the HTML document. LINK with @imports uses LINK to load proxy.css; proxy.css then uses @import to load the four stylesheets. Many LINKs has four LINK tags in the HTML document to pull in the four stylesheets (my recommended approach). The HTTP waterfall charts are shown in Figure 8 and Figure 9.

Figure 8. LINK with @imports

Figure 9. Many LINKs
Looking at LINK with @imports, the first problem is that the four stylesheets don’t start downloading until after proxy.css returns. This happens in all browsers. On the other hand, Many LINKs starts downloading the stylesheets immediately.
The second problem is that IE changes the download order. I added a 10 second script (the really long bar) at the very bottom of the page. In all other browsers, the @import stylesheets (from proxy.css) get downloaded first, and the script is last, exactly the order specified. In IE, however, the script gets inserted before the @import stylesheets, as shown by LINK with @imports in Figure 8. This causes the stylesheets to take longer to download since the long script is using up one of only two connections available in IE 6&7. Since IE won’t render anything in the page until all stylesheets are downloaded, using @import in this way causes the page to be blank for 12 seconds. Using LINK instead of @import preserves the load order, as shown by Many LINKs in Figure 9. Thus, the page renders in 4 seconds.
The load times of these resources are exaggerated to make it easy to see what’s happening. But for people with slow connections, especially those in some of the world’s emerging markets, these response times may not be that far from reality. The takeaways are:
- Using @import within a stylesheet adds one more roundtrip to the overall download time of the page.
- Using @import in IE causes the download order to be altered. This may cause stylesheets to take longer to download, which hinders progress rendering making the page feel slower.
First Week of Classes
I finished my first week teaching CS193H High Performance Web Sites at Stanford. It went well. The class is settling in at 35 students plus another 10 watching remotely through the Stanford Center for Professional Development. It’s 2/3 undergrad, 1/3 grad. The students are smart and ask great questions.
I’ve laid out the class schedule for the quarter. I post the slides before each lecture. Here are links to the slides from this week’s classes:
- Introduction (ppt, GDoc)
- The Importance of Frontend Performance (ppt, GDoc)
- HTTP and Web 100 Performance Profile (ppt, GDoc)
Today we kicked off the first class project. Each student picks five top web sites and records different performance stats in our Web 100 Performance Profile spreadsheet. We’ll update this again at the end of the quarter and analyze any trends.
I’m traveling to Boston next week for The Ajax Experience and won’t be able to teach class. I’m excited to say I’ve lined up three great industry leaders, speakers, and friends to appear as guest lecturers. Joseph Smarr (Plaxo) is doing a talk on “Performance Challenges for the Open Web”. Lindsey Simon (Google) is going to provide an introduction to CSS and talk about the balance between design and performance. Bill Scott (Netflix) has prepped a talk entitled “High Performance Examples from the Real World”, sure to contain great anecdotes and lessons learned from his work at Yahoo! and Netflix. Luckily the class is videotaped, so I can watch their classes when I get back.
See you in Boston!
Revving Filenames: don’t use querystring
It’s important to make resources (images, scripts, stylesheets, etc.) cacheable so your pages load faster when users come back. A recent study from Website Optimization shows that the top 1000 home pages average over 50 resources per page! Being able to skip 50 HTTP requests and just read those resources from the browser’s cache dramatically speeds up pages.
This is covered in my book (High Performance Web Sites) and YSlow by Rule 3: Add an Expires Header. It’s easy to make your resources cacheable – just add an Expires HTTP response header with a date in the future. You can do this in your Apache configuration like this:
<FilesMatch "\.(gif|jpg|js|css)$"> ExpiresActive On ExpiresDefault "access plus 10 years" </FilesMatch>
That part is easy. The hard part is revving your resource filenames when you make a change. If you make mylogo.gif
cacheable for 10 years and then publish a modified version of this file to your servers, users with the old version in their cache won’t get the update. The solution is to rev the name, perhaps by including the file’s timestamp or version number in the URL. But which is better: mylogo.1.2.gif
or mylogo.gif?v=1.2
? To gain the benefit of caching by popular proxies, avoid revving with a querystring and instead rev the filename itself. (more…)
OSCON: 34 hours in 37 minutes
I was in Portland for OSCON last week. There were many talks that attracted my attention – so many that I couldn’t get to them all. If you missed some talks, or didn’t make it to OSCON, check out this great effort capturing Oscon in 37 minutes. Gregg Pollack asked 45 speakers to summarize their talk in 30 seconds. Most people took longer (37 * 60 / 45 = 49.3 seconds), but still, to get a taste of 45 sessions in a 37 minute video is pretty awesome. If you had attended each session it would’ve taken over 34 hours! You can jump straight to the segment for any speaker (here’s mine), and links to each speaker’s slides are displayed.
High Performance Web Sites, Part 2
In my first book, High Performance Web Sites, I presented 14 rules for making web pages faster. I’ve got some good news and some bad news. Bad news first: there are more than 14 things you have to do to speed up your pages. The good news is I’ve started another book that describes more best practices for web performance. The working title is High Performance Web Sites, Part 2. Here’s the set of rules I have so far:
- Split the initial payload
- Load scripts without blocking
- Don’t scatter scripts
- Split dominant content domains
- Make static content cookie-free
- Reduce cookie weight
- Minify CSS
- Optimize images
- Use iframes sparingly
- To www or not to www
O’Reilly Webcast
This Thursday, April 24, at 10am PDT I’m doing a webcast entitled “Even Faster Web Sites”. This is a new type of event for O’Reilly and I’m excited to try it out. I’ll do 30 minutes of talking with online slides and demos, followed by questions from listeners. There is a limit to the number of people who can attend, so please register in advance.