We've recently been doing some optimization work on Camping.info to improve user experience through faster web site load times.
This post goes into the details of the optimization steps and their effect on the site's performance.
Measure, Improve, Measure again
To be confident that the changes we will introduce to Camping.info actually improve the performance or perceived performance of the site, we set up an automated test harness on TeamCity using the webpagetest API wrapper node module and a custom powershell wrapper script around that which collects the test results and reports them to TeamCity.
The following paragraphs will go into some detail on the concrete steps we took to improve our users's experience.
Include external script in existing bundle
The savings are humble but noticeable – the Time To Start Render drops from >1200 ms to 1100-1200 ms, which in practice will correlate with a slightly faster page appearance.
Host jQuery on your own server – or don't
Based on the previous improvement I assumed that saving a DNS lookup alone could already help in improving perceived performance. So for loading jQuery we switched from cdnjs.cloudflare.com to our own domain. It turns out though that this didn't have any impact on rendering or load times.
This is actually a tricky optimization – it depends a lot on who your audience is and what sites they visit. Loading e.g. jQuery from an external host will either save one request because the client's browser might have that resource cached after visiting a totally unrelated site that includes the same library, or your user will pay for an extra DNS lookup as compared to just loading the library from your own server. The decision is up to you.
Now, while the render start time did not decrease, the page load time decreased from around 1.8s to 1.5s. Thi is definitely a decent improvement but please don't overrate it – most of the page's content had probably already been loaded even in the old version. But now we can at least be sure that all Facebook assets will definitely be loaded only after all of the page's own assets have been loaded. And that's good.
It turns out that on a different page, the improvement after this single change is actually even more significant:
Here we can see that the deferred loading of the Facebook script actually improves not only the page load time, but also the start render and DOM content ready times.
One script is still being loaded before the onload event – Google Analytics. I couldn't quite convince myself to defer its loading until after onload, because we use it to track some user metrics and timings, and I felt that GA might not report the same quality of results if loaded too late. Please leave your opinions on this topic in the comment section.
Specify image dimensions inline to speed up rendering
The worst grade in our PageSpeed score was actually for not specifying image dimensions, neither in HTML nor in CSS:
So we went ahead and did that for the start page. Here's how that improved our score:
I honestly cannot tell any difference in performance with image dimensions provided. There are several possible causes for this:
- maybe the images in the above-the-fold content are loaded fast enough to not delay page rendering
- maybe the page's CSS allows the browser to start rendering even without knowing the exact image dimensions
- something that I have no clue about at the moment.
Loading CSS file from same domain
To speed up rendering it also seemed to be a good idea to deliver our site's CSS file from the same domain as the HTML, thus saving a DNS lookup during the early stage of page rendering. Actually, the start render time dropped a bit by doing that but unfortunately the page load time increased a bit indeterministically:
It's safe to assume that the additional load time was caused by the fact that all image resources that are referenced in our CSS were now also being retrieved from the main domain instead of the cookieless one which in turn delayed loading of other image resources. For now we reverted this change, but we know that we can further optimize the render process by serving out CSS even faster. It would probably also help a lot if we split our large CSS file into smaller ones that could be loaded per page.
Changes without performance impact
Todos for the next performance sprint
- combine and minify ASP.NET AJAX's ScriptResource.axd and WebResource.axd files
- load CSS from page domain but referenced images from cookieless domain (try css-url-rewrite)
- load less CSS per page – ideally inline the CSS needed for the above-the-fold content
- use HTML and CSS instead of images for our Google map buttons – this will save a ton of requests on the search page
Where are we at now?
Happy performance tuning!