How I improved Google Chrome & Firefox speed by 31.3%

| 12 min. (2544 words)

Over the past eight months, we’ve been pushing hard, creating as many pages as possible for our public site at Raygun.com. As we added and replaced more and more pages, I became curious about the potential public site performance impact.

As we already had Raygun’s Real User Monitoring (RUM) setup on the website, I figured I should take a look at the performance section to check metrics like page load speed and average load time.

After taking a look at our performance dashboard, I could see that we had room for improvement. Our average load time was 5.21s. I made some improvements and reduced the average load time by up to 31.3%.

In this article, I’ll write about the steps I took to make these improvements, all the benchmarks and the tools I used.

What made me look into our public site performance in the first place?

These were the initial stats that triggered me to look into some performance optimizations:

An average load time of 5.21s was a worry, (aim for three or less) so I decided to do something about it.

Measurement

Firstly I needed to decide what I wanted to measure, this would be the basis of my tests and would define the success of our public site performance improvements.

Using Raygun Real User Monitoring, I wanted to measure the following:

  • Median load time: The Median response time is what 50% of your customers experience (or faster). This is important because performance makes money – 40% of users will leave a website that takes more than 3 seconds to load!
  • Average load time: The site’s average page load time. It is measured by collecting load times at regular intervals across the date range. The load times are then added up and divided by the number of load times collected
  • P90 load time: Shows the 90% of your users experience this load time or less, within the date range
  • P99 load times: Medians are great, but we also need to appreciate the upper limit. I chose to track the P99 load time which is the time taken for the page to load for the 99th percentile of users. We want to make sure this number is around five seconds slow, not 25 seconds slow

We talk more about what you should be measuring in your software team here.

Ideally, our changes will show improvements in all these numbers however my primary focus is on improving the Median and Average load times.

Using Chrome DevTools I wanted to measure the time taken for the DOM content to load and also the overall Load time of the page. The reason why I choose to measure both these values is for two reasons:

  1. The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading_ (* Thanks to our reader Joacim for offering this suggested explanation.)_
  2. The Load trigger fires once all the additional logic on the page is complete. An example would be JavaScript’s .onLoad() function or jQuery’s .ready(). The reason why I want to track this value is that it will match up with what Raygun reports back so we will see a correlation between the data

Success

Now that we have some metrics to base our measurements off we now need to define success. To reduce the overall page load time is my biggest goal. But, if I can also get improvements on the DOMContentLoaded time, this would create a better user experience.

Browsers

Knowing what to measure is only the first step, now we need to decide in which environments to test our metrics. Thankfully Raygun’s Real User Monitoring enables us to find out which browsers our users are using. Taking a look at the browser tab on the Raygun application I can see that Chrome, Chrome Mobile, and Firefox are our top three browsers. These became the focus of the tests.

I’ve decided to test the following:

  • Chrome
  • Chrome with Fast 3G
  • Chrome with Slow 3G
  • Firefox
  • Firefox with Regular 3G

These environments should be enough to measure the improvements in multiple browsers and multiple devices.

Pages

The performance updates that I wanted to make would affect most pages on the website, but I had to decide which pages to measure. I decided to test two pages:

  1. Our homepage (/) – as this is the first page new users will see when they visit the site. Your homepage should be as fast as possible to ensure a good first impression
  2. The new Javascript language page (/languages/javascript) – as was a recently created page that needed optimizing

Baseline

Before making any performance improvements, I needed to get some baseline figures to compare my improvements. To make the measurements more reliable I decided to take each measurement multiple times with the cache disabled, then take the median of each metric and use that as the baseline.

My initial tests gave me the following results for my two pages:

Chrome

Homepage JS Language page
DOM content load Load DOM content load Load
2.97 4.32 3.36 4.52
2.37 3.71 3.39 4.77
2.35 3.24 3.65 4.54
2.7 4.04 3.26 4.6
2.48 3.82 3.28 4.19
Median 2.574 3.826 3.388 4.524

Chrome with Fast 3G

Homepage JS Language page
DOM content load Load DOM content load Load
6.9 9.21 8.87 12.34
6.29 9.78 8.94 11.25
6.28 8.58 8.9 12.37
Median 6.49 9.19 8.903333333 11.98666667

Chrome with Slow 3G

Homepage JS Language page
DOM content load Load DOM content load Load
23.23 36.49 31.78 41.21
22.48 31.58 31.59 43.78
21.95 34.13 32.42 40.55
Median 22.55333333 34.06666667 31.93 41.84666667

Firefox

Homepage JS Language page
DOM content load Load DOM content load Load
1.16 3.78 1.85 3.55
1.72 3.7 2.5 4.37
1.91 4.02 2.36 3.75
Median 1.596666667 3.833333333 2.236666667 3.89

Firefox with Regular 3G

Homepage JS Language page
DOM content load Load DOM content load Load
2.23 8.38 3.09 13.34
2.17 8.66 3.05 13.5
Median 2.2 8.52 3.07 13.42

Performance Improvements

Now that we have our baseline figures for our tests we can now get started on our performance updates. Using Raygun’s Insights feature, I was able to easily see what needed improvement with additional information on how to fix it.

The first thing I noticed was the that we weren’t properly caching static assets on the website. Our public site is built in ASP.NET, so this was just a matter of updating the Web.config file so that it includes the <clientCache>  element inside the <staticContent>  element. I could then assign how long I wanted the assets to be cached for, along with what mode you want to use. I added the following snippet to our <staticContent>  element to make our static assets stay alive for seven days, for more information you can check out the documentation here.

...
<staticContent>
  <clientCache cacheControlMaxAge="7.00:00:00" cacheControlMode="UseMaxAge" />
</staticContent>
...

To test that the asset caching is working as expected, I opened up the network tab inside Chrome DevTools then loaded up the homepage. I selected an image and took a look at the response headers.

~

As you can see we have the Cache-Control set to max-age=604800. If you do the math 604800s / 60 / 60 / 24 = 7 days. Great! The calculation seemed to match the values I set in the <clientCache>  element, so I could move on to our next improvement.

Adding font files

The next thing I noticed was that all our fonts were loaded in via the google fonts API. Serving these locally will reduce the amount of network traffic and improve page load speed (note: this depends on how fast your server is). As an added benefit if for some reason the fonts.googleapis.com API went down our font files would still get served. Localizing font files can be tedious, but thankfully there are some great open source tools out there to automate some of the processes for us. I used the Google webfonts helper tool, but there are many others out there similar to this, such as this bash script coded by Clemens Lang.

After adding the font files and @font-face styles to the solution and running grunt, I needed to test that my changes worked. I loaded up my local version of the homepage and the current production version of our homepage and did a side by side comparison. I then checked the console to make sure there were no 404 errors.

Localize the run_prettify.js script

My last change was to localize the run_prettify.js  script that we use to style our code snippets. Previously, this was loaded in via the rawgit CDN so localizing it was a straightforward process. I visited the CDN URL and saved the file to my computer, added it to the project solution and updated the run_prettify.js references. To test this, I loaded up one of our documentation pages and checked to see if there were any errors in the console and if the styles still worked.

Screenshot showing the JavaScript script for rg4js crash reporting

Testing Improvements

Now I made the changes it’s time to test them and see what the results look like and if we have improved our public site performance overall. I took the same amount of measurements for our second test, I then compared the median load times before and after, which would reveal the improvements gained.

Here are the figures I got back from my second round of tests with the cache disabled:

Chrome

Homepage Homepage JS Language page JS Language page
DOM content load Load DOM content load Load
2.26 3.18 3.36 4.26
2.27 3.19 3.36 4.26
2.27 3.17 3.39 4.28
2.44 3.34 3.42 4.32
2.49 3.41 3.44 4.33
Median 2.346 3.258 3.394 4.29

Chrome with Fast 3G

Homepage Homepage JS Language page JS Language page
DOM content load Load DOM content load Load
6.38 8.7 9.29 11.61
6.33 8.64 9.13 11.45
6.31 8.62 9.37 11.67
Median 6.34 8.653333333 9.263333333 11.57666667

Chrome with Slow 3G

Homepage Homepage JS Language page JS Language page
DOM content load Load DOM content load Load
23.6 31.76 32.34 41.93
23.72 31.89 32.36 41.77
23.67 31.85 32.16 41.73
Median 23.66333333 31.83333333 32.28666667 41.81

Firefox

Homepage Homepage JS Language page JS Language page
DOM content load Load DOM content load Load
1 2.88 1.42 2.73
1.14 3.22 1.67 3.12
1.15 3.07 1.71 2.75
Median 1.096666667 3.056666667 1.6 2.866666667

Firefox with Regular 3G

Homepage JS Language page
DOM content load Load DOM content load Load
1.94 7.88 2.85 12.77
1.95 7.91 2.06 12.45
Median 1.945 7.895 2.455 12.61

With this second round of tests, I also wanted to test the speed improvements gained from enabling caching of static content. So, I decided to also get some figures with the cache enabled. Unfortunately, because I didn’t take measurements from before with the cache enabled we aren’t going to see accurate comparisons but at least this will give me a rough idea on the impact adding  to our Web.config file had on our website.

Here are the figures I got back from my second round of tests with the cache enabled:

Chrome

Homepage JS Language page
DOM content load Load DOM content load Load
1.03 1.45 1.12 2.17
1.05 1.57 1.32 2.1
1.08 1.58 1.21 2.1
1.26 2.28 1.1 2
1.36 1.64 1.1 1.91
Median 1.156 1.704 1.17 2.056

Chrome with Fast 3G

Homepage JS Language page
Load 1.45 1.49
DOM 2.77 3.6

Chrome with Slow 3G

Homepage JS Language page
DOM content load 2.84 2.95
Load 5.65 5.75

Comparisons

Now that we have taken our measurements we can now compare both sets of data. I’m looking for exactly how much faster we have made these pages.

Chrome

Homepage JS Language page
DOM content load Load DOM content load Load
Before 2.574 3.826 3.388 4.524
After 2.346 3.258 3.394 4.29
Speed Improvement % 8.86% 14.85% -0.18% 5.17%

With cache enabled

Homepage JS Language page
DOM content load Load DOM content load Load
Before 2.574 3.826 3.388 4.524
After 1.156 1.704 1.17 2.056
Speed Improvement % 55.09% 55.46% 65.47% 54.55%

Page speed in Chrome with Fast 3G

Homepage JS Language page
DOM content load Load DOM content load Load
Before 6.49 9.19 8.903333333 11.98666667
After 6.34 8.653333333 9.263333333 11.57666667
Speed Improvement % 2.31% 5.84% -4.04% 3.42%

With cache enabled

Homepage JS Language page
DOM content load Load DOM content load Load
Before 6.49 9.19 8.903333333 11.98666667
After 1.45 2.77 1.49 3.6
Speed Improvement % 77.66% 69.86% 83.26% 69.97%

Chrome with Slow 3G

Homepage JS Language page
DOM content load Load DOM content load Load
Before 22.55333333 34.06666667 31.93 41.84666667
After 23.66333333 31.83333333 32.28666667 41.81
Speed Improvement % -4.92% 6.56% -1.12% 0.09%

With cache enabled

Homepage JS Language page
DOM content load Load DOM content load Load
Before 6.49 9.19 8.903333333 11.98666667
After 1.45 2.77 1.49 3.6
Speed Improvement % 77.66% 69.86% 83.26% 69.97%

Firefox

Homepage JS Language page
DOM content load Load DOM content load Load
Before 1.596666667 3.833333333 2.236666667 3.89
After 1.096666667 3.056666667 1.6 2.866666667
Speed Improvement % 31.32% 20.26% 28.46% 26.31%

Firefox with Regular 3G

Homepage JS Language page
DOM content load Load DOM content load Load
Before 2.2 8.52 3.07 13.42
After 1.945 7.895 2.455 12.61
Speed Improvement % 11.59% 7.34% 20.03% 6.04%

Summary

As you can see from the comparisons above our public site performance has improved from the changes.

These are the ones in green. However, you can also see a handful of stats have worsened. These are the ones in red.

The numbers that increased were likely caused by the localization of assets (fonts and scripts). We can only see it after the effects on the DOM content load. So, basically when the browser is fetching all the required assets and rendering the page.

As for the numbers that decreased, our improvements had a more significant impact on Firefox compared to Chrome. Overall I saw an excellent speed improvement on all pages and devices.

Looking at the comparison of our cached pages, we see some pretty significant improvements. As I said before these won’t be 100% accurate. But seeing an average of 65% decrease in overall page load time is relatively substantial.

The page profiling tool in Chrome DevTools allowed me to break down the improvements and get more granular information. The results show improvements in almost all areas, as shown below:

Homepage

Before After
Screenshot showing the public site performance improvements shown in Chrome Dev Tools Public site performance improvements shown in Chrome Dev Tools

JS Language page

Before After
Screenshot of the public site performance improvements shown in Chrome Dev Tools Public site performance improvements shown in Chrome Dev Tools

Wrap up

Unfortunately, I wasn’t able to measure every page on the website. Therefore, I don’t know if these improvements would be the same site-wide. But, thankfully, I can compare Raygun’s Real User Monitoring performance tab with the snapshot we collected earlier.

Here is what the Real User Monitoring performance dashboard looked like before:

Screenshot showing the Before stats of the the public site performance improvements shown in Real User Monitoring

And here is what the public site performance looks like after:

Screenshot of public site performance improvements shown in Real User Monitoring

The two performance dashboards show I have speed improvements on all measurements:

  • Median load time reduced by 25ms
  • Average load time reduced by 90ms
  • P90 load time reduced by 98ms
  • P99 load time reduced by 20.13s

Overall, I’m happy with the optimizations. However, there is still room for improvement. Next time I plan to ensure image optimization on all pages. I’ll also look at combining scripts, minification on all CSS and JavaScript assets and make optimizations to the script and style order. zow!

Thanks for reading!

Saving customers 75 hours per month with Real User Monitoring