Only 5% of the end-user response time is spent fetching the HTML document. This result holds true for almost all web sites. The most part of websites spend less than 20% of the total response time getting the HTML document. The other 80+% of the time is spent dealing with what's in the HTML document, namely, the front-end. That's why the key to faster web sites is to focus on improving front-end performance. (thanks YAHOO!)
There are three main reasons why front-end performance is the place to start.
- There is more potential for improvement by focusing on the front-end. Cutting it in half reduces response times by 40% or more, whereas cutting back-end performance in half results in less than a 10% reduction.
- Front-end improvements typically require less time and resources than back-end projects (redesigning application architecture and code, finding and optimizing critical code paths, adding or modifying hardware, distributing databases, etc.).
- Front-end performance tuning has been proven to work.
The performance golden rule is: optimize front-end performance first, that's where 80% or more of the end-user response time is spent.
Based on this "golden rules" me and Brian Chan decided (while the New Year's Eve party) to give a New Year's present for Liferay community and start a serie of performance improvements on our front-end.
1. Using CSS Sprites
CSS Sprites are the preferred method for reducing the number of image requests. Combine your background images into a single image and use the CSS
background-position properties to display the desired image segment.
We have a new property called
theme.images.fast.load. Defaults to true in normal usage and false in development. When the server startups, two files are automatically created on each image folder of your theme ".sprite.png" and ".sprite.properties". These files are only recreated if needed. The taglibs are programmed to know to automatically read the "packed.sprite" and display that relative file on the "packed.png" if this feature is enabled.
This will significantly enhance load time (http://css-tricks.com/css-sprites-what-they-are-why-theyre-cool-and-how-to-use-them/).
You can perceive the benefits when you see
theme.images.fast.load in action, In a very simple page the number of requests decrease from 59 to 33 and the load time from 885ms to 811ms, in a big page with a lot of contents and hundreds of images it will cause a huge difference.
( without using
2. Cache Filter: Caching Strip Filter and Compress filter
Liferay Portal take advantage of server filters to manipulate headers, strip spaces from the content and even for gzip the content. These filters are doing a good job actually, however, these filters can run us into a problem. Filters are applied on each file on each request, it's very expensive for the server for both processing and memory.
In the old scenario, basically, the first filter applied was the Header Filter that is the most important because it saves the cache on the client-side, after the Strip Filter and the Compress Filter were being applied.
( Old scenario - Represents the priority/order without CacheFilter )
Now, in the new scenario, the CacheFilter instead of compressing / stripping per request on static data that has not changed, we know cache the bytes and content encoding and fetch it if the original data has not changed.
( New scenario - Represents the priority with CacheFilter )
This brings significant performance improvements to the server. This filter is cached on the server, it means - all users will take advantage of this technics, for instance, saving 50ms per request, and if the server has an avarage of 10000 request/hour this server will save 500000ms/hour (8.3 minutes/hour) of processing.
The graphic below resumes local tests I did today. Basically, the graphic compares how many milliseconds are spent when the filter are being used and when it's not, for different file sizes requests.
The results are promising, we need the community's help to test and see this improvements in action on live websites on a real enviroment.
3. Put Scripts at the Bottom
The problem caused by scripts is that they block parallel downloads. The HTTP/1.1 specification suggests that browsers download no more than two components in parallel per hostname. If you serve your images from multiple hostnames, you can get more than two downloads to occur in parallel. While a script is downloading, however, the browser won't start any other downloads, even on different hostnames.
It's important to remember that Stylesheets should be on top (vide, YAHOO).
4. For static components using "Never expire" header
There are two things in this rule:
- For static components: implement "Never expire" policy by setting far future
- For dynamic components: use an appropriate
Cache-Control header to help the browser with conditional requests
A first-time visitor to your page may have to make several HTTP requests, but by using the Expires header you make those components cacheable. This avoids unnecessary HTTP requests on subsequent page views. Expires headers are most often used with images, but they should be used on all components including scripts, stylesheets, and Flash components.
Browsers use a cache to reduce the number and size of HTTP requests, making web pages load faster. A web server uses the Expires header in the HTTP response to tell the client how long a component can be cached. Keep in mind, if you use a far future Expires header you have to change the component's filename whenever the component changes. Or concatenate timestamps to the url.
Using a far future Expires header affects page views only after a user has already visited your site. It has no effect on the number of HTTP requests when a user visits your site for the first time and the browser's cache is empty. Therefore the impact of this performance improvement depends on how often users hit your pages with a primed cache. (A "primed cache" already contains all of the components in the page.) The number of page views with a primed cache is 75-85%. By using a far future Expires header, you increase the number of components that are cached by the browser and re-used on subsequent page views without sending a single byte over the user's Internet connection.
These are the most important stuffs we worked on these first days of 2009.
I'm sure these are important steps for improving the UI performance and they sounds like prosperation for our product.