At the Forge

Client-Side Performance

Reuven M. Lerner

Issue #261, January 2016

Give your users a better experience by improving client-side performance.

In my last few columns, I've covered different ways to understand, analyze and improve the performance of your Web applications. I've shown that between your network connections, server hardware, database design and HTTP server configuration, you can change and improve the performance of your Web application—well, sort of. Web applications, when they first started, were dynamic only on the server side. Sure, they output HTML—and later, CSS and JavaScript—but the overwhelming majority of the processing and computation took place on the server.

This model, of course, has changed dramatically in the last decade, to such a degree that you now accurately can claim to be a Web developer and work almost exclusively in HTML, CSS and JavaScript, with little or no server-side component. Entire MVC frameworks, such as Ember.js, Angular.js and React.js, assume that you'll be writing your application in JavaScript and provide you with the objects and infrastructure necessary for doing so.

If you're worried about the performance of your Web application, you need to concern yourself not only with what happens on the server, but also with what happens in the browser. Some commercial performance-monitoring solutions already take this into account, allowing you to see how long it takes for elements to render, and then to execute, on your users' browsers. However, there is also no shortage of open-source tools available for you to check and improve the ways in which your client-side programs are executing.

This month, I'm concluding this exploration of Web application performance with a survey of things to keep in mind, as well as tools that help ensure that you're actually doing what you should be.

Client-Side Considerations

Client-side code is written in JavaScript. The code, whether inline in <script> tags or retrieved from a remote server, executes whenever the browser's parser gets to that part of the page. If you have JavaScript at the top of the page, it'll be executed when the parser gets to it, potentially delaying the rendering of the rest of your page. By contrast, if your JavaScript is at the bottom, the parser will execute it only after parsing and rendering the rest of the page. This is why so many developers learned to put their JavaScript commands inside a “document-ready” callback function; in that way, the code was executed only once the entire page had been loaded.

Because so many modern Web applications take place in JavaScript, the fact that you're often loading JavaScript from remote servers means that the time it takes to render a page depends not just on the server speed, the network bandwidth and the page's complexity, but also on the servers and networks serving such JavaScript, as well as those pages' complexity. As a result, it's generally considered to be good practice to load as many libraries as possible late in the game, at the bottom of your HTML page. That is, instead of having your <script> tags, whether local or remote, at the top of your page, you should put them at the bottom—unless it's vital to do otherwise.

Even better, you should consolidate your JavaScript files into a single file. This has a number of advantages. It means the user's browser needs to download a single file, rather than many of them. If you include all of the JavaScript needed on your site in a single file, it also means that the file needs to be loaded only a single time. On every subsequent page load, the JavaScript will be mentioned, but it won't be downloaded, because it'll already be cached in the browser's memory. You can make things even better, of course, by compressing that single JavaScript file. This turns out to be extremely effective, because compression algorithms work well with text, and especially with text that repeats itself, as happens with program code.

Better yet, you can run JavaScript code through a minimizer (or “minifier”), which removes comments, extraneous whitespace and anything else that isn't necessary for client-side programs to run. By minifying JavaScript files, combining the files and then compressing the resulting combination, you can dramatically reduce the size of the JavaScript being sent to the user's browser and ensure that it is loaded only once per visit to your Web site.

UglifyJS, for example, can be installed via npm:

npm install uglify-js -g

You can run it on a file with:

uglifyjs FILENAME

Although because that sends output to stdout, you'll likely want to redirect it to a file:

uglifyjs FILENAME > ugFILENAME.js

I took the JavaScript from my PhD dissertation software and ran it through both uglifyjs and gzip. The original 36KB file was 8.5KB after compression, but 6.0KB after uglifying and compression. Although you might scoff at the small size of a 36KB file in the modern world, the fact is that each file takes time, for both the browser and the server. The faster you can get it off your server and into the browser, the better.

Download Time

Once the JavaScript is in the user's browser, things are both easier and harder to analyze. On the one hand, you (the developer) can download the program, test it and check the performance—and then, you also can use in-browser debugging tools to test and improve things.

One of the most important tools offered by both Chrome and Firefox is the display of files being sent to the browser. Even if your site appears to be loading and rendering quickly, a quick look at the download timeline almost certainly will be somewhere between surprising and shocking to you. You'll see how long it takes for each of the JavaScript (and CSS, and image) files to download and, thus, how much time it takes between the user requesting your page and the content actually appearing on it. This is a great way for you to identify potential bottlenecks and then reduce their effect on the slowness (or apparent slowness) of your site.

Even New Relic, which normally is considered a (commercial) server-side performance monitor, now offers some client-side performance checking. You place a small piece of JavaScript on your site; New Relic collects this information, and then tells you how long it took for your content to get to the user's browser and how long it took to render. This provides a surprisingly insightful view of whether you need to work on improving the speed with which your files are delivered or to optimize the code further, such that it runs faster. There definitely are other options, but I've found that even the free (not open-source, but free of charge) New Relic client-side benchmarking to be quite useful and helpful.

Once you have combined and compressed your JavaScript files, you seriously should consider putting them, as well as any other static assets (such as CSS files and images), on a content distribution network (CDN). A CDN handles only static content, but given how many large, slow-to-download files are static, that often can provide a significant improvement. CDNs not only have a great deal of bandwidth, but they also copy your content to multiple servers, using the geographically closest one to serve content to your user. Thus, a user in Tokyo will receive data from a local CDN server, whereas a Chicago-based user will receive it from a different CDN server. So, using a CDN reduces the load on your main Web server, while decreasing the actual and perceived download times.

Benchmarking JavaScript

Although JavaScript has a (well deserved, I think) reputation for being a frustrating and quirky language, the fact is that modern JavaScript implementations run very quickly—assuming that you use the language in the right way. However, it's sometimes hard to know where your program is spending most of its time. Fortunately, the Chrome developer tools (a part of the Chrome browser) include a profiling tool. Go to the “profile” tab in the developer tools, and select the CPU option before visiting your site. You can run through your site for a few seconds or minutes before stopping the profiling from taking place. Once you've done that, you'll get a (very long) indication of which JavaScript programs were running, where they came from and how much time the CPU spent in each one.

You similarly can ask the profiler to examine memory usage. The more complex the application you're writing, the more necessary these tools will be. At the same time, you'll likely find that when you profile your JavaScript code, the most frequently used code probably will be code you didn't write yourself, but rather that is part of the underlying framework you're using.

In Firebug, the Firefox-based debugger, you can profile a page by going to the “console” tab and clicking on “profile”. You'll see a table showing how much time was spent in each function, and what percentage of the total time was spent there. If you're a Chrome user, you can open up the developer tools and click on the “profiles” tab. You'll then need to choose whether you want to check CPU performance or memory performance (in two different flavors). After starting and stopping the profiler, you can analyze the resources that JavaScript used—and then, of course, change your code appropriately.

One tool I have begun to use more frequently is PageSpeed from Google. This collection of tools would appear to be an SaaS, an updated version of YSlow, which was my go-to tool for many years. For example, Google's tools will tell you how mobile-friendly your site is.

Moreover, the PageSpeed results always point to documentation that describes, in great detail, why issues are problematic and what steps you can take in order to fix them. This documentation is surprisingly well written, and it points to very practical, clear suggestions for how to improve the performance of your JavaScript and CSS. After running PageSpeed against one of my client's sites, I found that we still had some blocking JavaScript higher up than is perhaps necessary. It also suggested which images could be compressed and how much space we would save in so doing.

Summary

Although server-side programming still is a vital part of the Web, the client is where much of the action is, and where the user often perceives lags and slowness. As a result, it's worth investing time to check your client-side performance and to address problems before your users start to complain (or leave you without complaining). Using a variety of tools to check your performance, as well as to reduce the size and time of JavaScript and CSS downloads, will go a long way toward improving your users' satisfaction with your site.

Reuven M. Lerner trains companies around the world in Python, PostgreSQL, Git and Ruby. His ebook, “Practice Makes Python”, contains 50 of his favorite exercises to sharpen your Python skills. Reuven blogs regularly at blog.lerner.co.il and tweets as @reuvenmlerner. Reuven has a PhD in Learning Sciences from Northwestern University, and he lives in Modi'in, Israel, with his wife and three children.