#369 Client-Side Performance pro
- source codeProject Files in Zip (63.5 KB)
- mp4Full Size H.264 Video (35.4 MB)
- m4vSmaller H.264 Video (19.7 MB)
- webmFull Size VP8 Video (22.1 MB)
- ogvFull Size Theora Video (52.5 MB)
In the previous episode we used MiniProfiler to find the slow portions of a Rails application and optimize them. Improving the performance of the code on the server is only half the battle, however, much of what makes a web page feel slow can be on the client side in the loading and parsing of the resources. In this episode we’ll show you several tools for analyzing what’s going on in the browser and give you some tips on how to improve performance so that your site will feel even faster.
We’ll demonstrate this using the Railscasts site. Our goal is to determine what goes on when its home page loads and what we can do to improve its performance. We’ll use Google Chrome to do this as it has useful developer tools for analyzing a web page. The first thing we’ll look at is the network tab. If we click this then reload the page we’ll see a waterfall report showing what happened while the page loaded.
The page took just over a second to load completely and we can see the various requests here and how long each one took to process. Each bar in the timeline is made up of two parts. The first lighter section shows the time between the request being made and the response beginning while the second section shows the time spend processing the response. We can hover over any of the bars for more details about where the request spent the most time. As far as Rails is concerned this request took around 200ms to process this time and while this time could probably be improved that’s only a fraction of the total time that the page took to load. We’ll take a look at what happens during the rest of this time.
There’s more to this story than what we see here. If we hover over a lot of the bars the darker section shows 0ms and this is because Chrome is reading files from the cache instead of using the full response from the server. This means that we’re not getting an accurate representation of the performance that someone coming to the site for the first time will experience. This is even more obvious if we visit this page by clicking a link to it instead of reloading it. If we do this most of the page’s assets will be fetched from the cache without making a request to the server.
It’s useful to see how caching affects performance but if we want to get the perspective of a first-time visitor we can turn off caching in the developer tools’ settings. If we do this then reload the page again the cache won’t be used. This time the page takes around 1.3 seconds to load and the dark sections of the bars are longer as everything is loaded in from the server.
There are several ways that we can analyze this output to help us improve the page’s performance, but before we do that we’ll show another way to generate a waterfall report without using Chrome. On the WebPageTest site we can enter a URL and specify a location and browser and the site will tell us how the page loads for those settings. We can even customize other settings such the connection speed. The test make take a minute or so to run but once it completes we’ll see the results. The test loads the page twice. In this case the first view took around 2.5 seconds while the second took around 1.2 seconds thanks to caching. There are also waterfall graphs for each load along with a screenshot.
If we click on the first waterfall graph we’ll be taken to a page similar to the graph we saw in Chrome. WebPageTest does more than just this, though, it also grades our application in a variety of areas. The Railscasts site does well in all areas apart from caching static content so lets take a look at that. We can click on the area that has scored badly to get more details about why it has done so and when we do it turns out that a lot of the images on the page don’t have a
Expires header in their response. This is something that the asset pipeline helps us with but we aren’t using it for all the images. To fix this we could configure the web server to add an
Expires header for these images. To learn more about HTTP caching and how response headers work take a look at episode 321.There’s much more information in the test results about each request and whether they pass certain tests.
There are other tools that give this kind of information and one of these is available within Chrome’s Developer Tools. If we click the “Audits” icon then reload the page we want to analyze we’ll be given several suggestions as to how we can improve the page’s performance, including the one we saw earlier about using browser caching.
This tool also suggests that we move some of the assets to different domain names so that their downloading can be done in parallel by opening more connections. On a similar note if we move the static assets to a domain which doesn’t match the cookies then the client won’t send the cookies for each request to the static assets. This is more critical is we have a lot of large cookies matching the domain.
The tool also warns us about images that don’t have their width and height specified in the HTML. Fixing this will make the layout more consistent while the page loads. Another useful feature it has is the ability to find the CSS rules that aren’t used on the page. Unless they’re used elsewhere we should consider removing these to reduce the size of our application’s stylesheets. Episode 180 covers this is more detail.
That’s it for the audit tool but there are other tools that we can use to analyze our page. One of these is Google’s PageSpeed Insights. This can be used online or as a browser extension. We’ll install the extension for Chrome; Once we’ve done so the best way to use it is in the Developer Tools. There’ll be a new PageSpeed button on its toolbar and if we click it it will analyze the current page and generate a report. Some of the things mentioned in this report are the same as we’ve seen in other tools but there are other suggestions listed such as combining images into CSS sprites. The report even lists the images that we should be combining. Each the suggestions this tool makes links to a page that has more information about that optimization, why we should use it and the tools we can use to implement it. Episode 334 has more information on CSS sprites.
PageSpeed also gives us tips on optimizing images. A number of images on the page can be compressed further without any loss in quality and PageSpeed will list these, along with a indication of how by how much the image can be reduced in file size. There’s even a link to the compressed version of the image.
application.js file. There are also tools that can help with these dependency issues, such as RequireJS.
Our new partial file looks like this:
jQuery -> $('#tasks input[type=checkbox]').click -> $(this.form).submit() true
This code listens to each checkbox’s
click event and when this fires the form that the checkbox is on is submitted. As the form is marked as
jQuery.extend.ready callback which triggers the code we showed earlier takes around 31ms. This isn’t too bad but we can probably reduce it. Instead of manually triggering the profiler we’ll trigger it in code. This is done by calling
console.profile and passing in a name to start profiling and then calling
console.profileEnd to stop profiling.
jQuery -> console.profile("Task checkboxes") $('#tasks input[type=checkbox]').click -> $(this.form).submit() true console.profileEnd();
Now we don’t even have to start the profiler. If we reload the page it will now insert a profile entry automatically. This shows this code taking 22ms to run this time and what’s nice about this approach is that it isolates just the code we’re interested in. With this focussed profiling in place we can experiment with performance. Instead of listening to the checkboxes’
click event we’ll use on, like this:
jQuery -> console.profile("Task checkboxes") $('#tasks').on 'click', 'input[type=checkbox]' -> $(this.form).submit() true console.profileEnd();
When we reload the page now it will run the profiler again and now this piece of code only takes 2ms to process. This seems to be much faster but it might just be deferring the time until the
click event happens.
To help us to work this out we can use another tool for analyzing performance called Speed Tracer. This is another Chrome extension and once we’ve installed it we’ll have a button in the toolbar that we can click to start it recording. Once it’s running we’ll click one of the checkboxes on the page then click it again to stop it. We can now see all the events that took place while Speed Tracer was running. One of these was the
click event and Speed Tracer will show us the details of what happened for this event.
click event in this application.