If it wasn't your priority last year or the year before, it's sure to be your priority now: bring your Web site or service to mobile devices in 2013 or suffer the consequences. Early adopters have been talking about mobile taking over since
Of that data, the lion's share is consumed by iOS and Android devices, which suggests a focus for any immediate Web development efforts. Figure 2 shows megabytes downloaded per month in 2011 and 2012, indicating that these platforms are widely used and trending upward.
So, piece of cake, right? Just take some of the great literature on writing desktop Web sites and apply it to mobile. For example, Yahoo!'s excellent YSlow tool and corresponding performance rules8 are an excellent starting point; Google's PageSpeed provides similar guidelines.5
The best practices for optimizing Web site performance, as articulated in YSlow and PageSpeed, were developed largely with the desktop world in mind. Now that mobile devices need to be accounted for as well, some of those practices might not have the intended
Mobile users expect a more
Although the recommendations in Google's PageSpeed and Yahoo!'s YSlow work well for desktop development, some of them need to be reconsidered to provide maximum benefit for mobile development. Network connectivity, while far more ubiquitous than ever before, is still spotty; a mobile site needs to compensate for this problem so users generally feel that the app is responsive even when the network is not. Older phones parse and execute JavaScript 100 times slower than desktops, and even the latest phones are still slower than desktop devices by a factor of 10—and this slowdown magnifies the smallest of sins. Handling JavaScript and network problems well will bring your performance within the expectations for any native mobile app. Then all that will remain is a host of
With these thoughts in mind, let's consider how YSlow and PageSpeed guidelines apply to the world of Android and iPhone
A core recommendation from both Google and Yahoo! is to minimize HTTP requests. This is a critical concept that needs special expertise and care to be effective on mobile. The good news is that existing recommendations on using CSS sprites to represent images embedded as
Image maps should work as well, but their inflexibility in terms of layout options is a bit of a drawback for mobile. For example, for a truly slick mobile experience you'll want to make good use of orientation changes that affect the horizontal dimension of your Web page. With image maps you would either have to use two of them or dice them up, in which case you might as well use CSS sprites and do your layout with markup as usual. So while image maps should work as a technique, on the whole sprites work better.
These existing techniques alone will not be enough to supercharge page load on mobile. On iOS, for example, pages are cached in memory only, and HTML files still appear to be limited to 25 KB uncompressed (though other resource types can be much larger now). In addition, some iOS devices are still limited to a maximum of four parallel connections to download your content—which means that you can't afford to rely on multiple external sources to load in a reasonable amount of time. Finally, the HTTP 1.1 specification recommends at most two parallel downloads per hostname. Of course these values are changing all the time; to find tools and data on the latest limits, Steve Souder's Mobile Cache File Sizes7 and Ryan Grove's Mobile Browser Cache Limits, Revisited6 are good starting points.
If you truly want to solve the cache issue, it's important to force the mobile browser to cache all the unchanging content on a site permanently, using HTML5 application cache, commonly referred to as app cache. Because app cache is still on the bleeding edge, it is best to use the minimal subset possible for your application.
The cache is controlled by a single manifest file that tells the browser where to get resources. The minimum functionality would be to make your Web site load as a single large Web page, and have the manifest file list that page and a hashCode as a comment that is updated when the Web page changes. Dynamic content can be loaded via XHR (XMLHttpRequest) and inserted into the document. This technique is most effective if you design the prefix of your page (up to about the 1,400th byte, in order to fit into a single packet across almost any TCP/IP network) to render a basic framework for the page before any script is executed.
If you design your site in this way, you can also have the framework of the page fade in by providing an opacity transition from 0.0001 to 1.0 just after the framework of markup is loaded. This will create a very slick
<script>
if (window.applicationCache.status == 0) {
// Page was loaded from the Network; reveal the spinner
} else {
// Page was loaded from AppCache; heavier-weight startup applies
}
</script>
Using this pattern ensures that the user will immediately get the feedback that your page is loading, thus reducing the chance of abandonment at the most critical moment: when the user first discovers your site.
To complete the effect, you also need to ensure that your serving infrastructure flushes the framework of the page to the network before doing any heavy lifting on the server side, so that all overhead on first request is deferred until after the initial packet is sent. This will prove remarkably speedy even on spottier connections. It's also not a bad idea to make a request to the server at this point to track the
Following the recommended pattern means that even on the first load, all code, assets, and CSS for your site will load in a single round trip, and that will create the best possible mobile experience. Dynamic data will of course have to be loaded separately, and the same level of care and caching should apply there, too, except that HTML5 storage APIs will have to be used to cache
Page Speed's best practices for minimizing
The last item in that section of Google's recommendations focuses on parallelism achieved by serving from multiple hostnames, but parallel downloads are likely to prove ineffective for mobile devices. Combining your resources and components into single files and ensuring that they are served from app cache will be the most effective technique.
Compressing all content that would benefit (essentially everything except images and video) remains a great recommendation for mobile. Mobile CPUs are getting faster much more quickly than mobile networks, and their speed doesn't change when a user is visiting the cottage. Even if you've diligently used app cache and local storage to save all resources locally on the device, you can expect the user will be regularly loading dynamic content, and all those requests should be compressed. To speed initial load time, even cached content should be delivered compressed whenever possible, though the benefit is less.
After caching and compression, script loading is likely to be the single biggest source of performance degradation for a Web site, and it is the hardest to address. The big issue on mobile is that parse and execute times of script are much slower than one would expect. In fact, the rule of thumb is that parsing and execution are 10 times slower than when testing on a desktop. A JavaScript payload of as little as 100 KB can cost 100 ms of startup time even on reasonably recent phones such as iPhone 4— and the previous generation of iPhone was 10 times slower!
Therefore, it is certainly worth putting the vast bulk of script at the bottom of the page. To evaluate parse time, you can use two script tags as follows:
<script>
var start_checkpoint = new Date();
</script>
<script>
var parsed_checkpoint = new Date();
// more script here
var eval_checkpoint = new Date();
var parse_time = parse_checkpoint - start_checkpoint;
var eval_time = eval_checkpoint - parse_checkpoint;
</script>
The start checkpoint is parsed and evaluated before parsing for the second script tag begins. The second script is then loaded and parsed, and the time is recorded in the parse checkpoint (which technically includes a tiny bit of execution of the second script tag, but this is neglected and billed to the parser). The eval checkpoint is recorded only after your business logic has all been evaluated.
Chrome on Android now offers a much more powerful technique to debug startup time: using window.performance to read
It is highly instructive to look at these numbers to appreciate how bad parse time is, and then to apply tricks to avoid parse latency. The most powerful of these tricks is allowing the browser to load your JavaScript without recognizing it as script and defer parsing and initial evaluation to a time of your choosing.
There are two methods for accomplishing this. The older one is commenting out your JavaScript and using another block of script to uncomment the content of the tag only when it is needed, as described in the Google mobile blog in 2009.3 More recently, a cleaner technique has been used for the same purpose. It involves setting the type of the script to an unrecognized type and changing it to text/JavaScript later. In this approach, you start with script blocks that look like this:
<script type="deferred" id="module1">
var start_checkpoint = new Date();
</script>
When you are ready to use the script, the JavaScript finds the script tag and modifies the type, which causes the browser to parse and evaluate the script.
By putting your deferred script at the bottom and uncommenting it only when needed, you can very effectively amortize the cost of using JavaScript across the runtime of your application. If your modules are small enough, this technique is cheap enough to be applied at the moment the user first clicks a button or link that needs the script, which can be uncommented, parsed, evaluated, and executed with no noticeable latency.
One of the easiest ways of introducing unexpected latency into a site is to inadvertently cause the browser to lay out the document. Seemingly innocuous JavaScript can trigger style recomputation in the midst of execution, while a rearrangement of the same code can be much more efficient.
The rule of thumb is to avoid reading properties that rely on the position of elements on the page to be returned, because any such property could cause the browser to recalculate styles on demand and return the value to your script.
The easiest way to inspect examples of this problem is to use the developer tools in Chrome. Ryan Fioravanti's excellent Google I/O presentation2 details how to do this by using adb (Android Debug Bridge) to forward a port on a desktop machine to the development tool port on the Android Chrome browser. Once that is set up, the Events timeline can be used to spot Layout events followed by large gaps of time that represent style recalculation. In the example in Fioravanti's talk, paying attention to when style recalculation was happening made the event handler in question twice as fast.
The focus so far has mainly been on the size of responses to the client and how long the client takes to process data on the client side. Request size can also be a problem, particularly for sites that use a large number of cookies alongside every request. This is easiest to monitor on the server side, and ideally all requests made to the server should be much smaller than a single TCP packet.
Preloading components is most effective when the user's workflow is almost certain to cause a predictable action just after the initial page loads. For example, in a news site certain articles will have a large
Another example of this is the AJAX version of the mobile Google Calendar Web site, where the next day's events are loaded as the user clicks through each day. The effect is that the user can easily walk through the week and see the data load instantly. You can compare this to the non- preloaded case by using the month view to jump ahead a few days at a time, exposing how slow it can be to take a round trip to the server to serve the same quantity of data. The round trip involves a noticeable spinner even over
Particularly for dynamic images, applying the best compression available will pay off handsomely in overall page speed. You can test image quality on a device to determine if there is a noticeable difference between 50 percent JPEG quality and 80 or 90 percent, and note the significant reductions in size that can be achieved. Even dramatic reductions in JPEG quality are often not visible, and the savings can be as much as 40 percent of the file size. Similar advice applies to .PNG and .GIF files, though these are used less for dynamic content (and therefore they are served from app cache and are not as sensitive to size).
Almost every recommendation in Google's "Optimize Browser Rendering" section applies perfectly to mobile, particularly the concerns about needlessly inefficient CSS. There is a tradeoff to consider, however: using a complex CSS selector can avoid a DOM (Document Object Model) modification.
While Google considers complex CSS selectors inefficient, they are fast compared with doing the equivalent work in JavaScript on a mobile device. In cases where the CSS selector isn't being used to avoid JavaScript execution, Google's recommendations apply.
Ideally, a site would load with 0 DNS lookups, as each represents a round trip with the potential to block all other activity. Minimally, however, a DNS lookup will fetch the manifest file, which is done in parallel with page load as the browser brings in resources from the application cache. So it's fairly safe to use the name of your host site and assume that it will be in the system's DNS cache whenever the device is online.
If you rely on using multiple hosts to parallelize content loading, you may need one more hostname lookup. There is no point using more than two hosts to parallelize content loading since in the best of cases you're likely to be limited to four simultaneous connections. A second DNS lookup is probably preferable to hardcoding the IP address in your application. This would cause all content to download every time your servers moved and would make it impossible to make good use of any CDN (content delivery network) you may be using to serve data. On balance, the recommendation here is to stick with a single hostname for serving all resources, as the benefit from using multiple hostnames to get more parallel downloads is small relative to the implementation complexity, and actual speed gains are unlikely to be significant over poor networks.
Minification is beneficial for mobile, though the biggest effect is seen in comparing uncompressed sizes. If minification poses a challenge, be sure to compare the sizes only after applying gzip to get a realistic sense of the gains. They may be below 5 percent and not worth the extra serving and debugging complexity.
Some recommendations depend on the context of the particular project and should be used only on certain sites.
Using
If you need to create image tags that contain a dummy image, use a data URL to encode a small image in place of an empty string until you can replace the image source.
The
Some of the guidelines for desktop development don't apply when building mobile sites.
This is one recommendation that can't really be followed on mobile. Because of a healthy distrust of the mobile device's browser cache policy, it will almost always turn out best if you cache your JavaScript and CSS manually; thus, inlining it all into the main page will deliver the best results in terms of speed. For maintenance reasons, or perhaps if a site has
Redirects are a source of round trips and should be avoided at all costs. Regularly monitoring the response codes from your servers should make it possible to catch redirect mistakes, which are commonly caused by poor URL choices, authentication choices, ads, or external components. It is better to update the site's script and resources and let app cache download and cache all the new locations than to deliver even one redirect return code per user visit. Redirects can also cause unexpected effects with app cache, causing the browser to download the same resources multiple times and store them in the database. This is easiest to test for on the desktop where the sqlite3
YSlow also recommends avoiding duplicate scripts. Certainly after all the effort made to minify, obfuscate, and manually cache your script tags, it will be worth ensuring that the browser isn't parsing and evaluating the same piece of script twice. Removing duplicate scripts remains a solid piece of advice for mobile sites.
In the case of ETags (entity tags), the removal advice is the bit that applies. As you're already storing all the resources in app cache, and app cache is separate per host domain, there is no benefit to using
Rather than trusting the browser to cache AJAX responses, it's best to build either a
We've already discussed parallel downloads, and the opportunity for leveraging
Reducing cookie sizes applies to mobile just as it does to the desktop. Specifically, be sure that the cookies for a page do not, in aggregate, cause any requests to be split across multiple packets. Aim for 1,000 bytes or less of cookie data.
Despite the existing recommendation stated in the title above, for absolute speed on mobile, neither link nor @import is appropriate. Instead, inline styles in the main body of the page create the fastest load time and the most
As mobile devices don't support multipart documents, app cache is required.
With these extensive modifications to the guidelines, the YSlow and PageSpeed recommendations may seem to have very little application to mobile Web development. Quite a few recommendations can still be effective for mobile, however, depending on your requirements. Here is a list of recommendations from YSlow that can still be useful for mobile sites:
• Use a CDN
• Add an expires or cache-control header
• Put style sheets at the top
• Avoid redirects
• Remove duplicate scripts
• Flush the buffer early
• Use GET for AJAX requests
• Postload components
• Reduce the number of DOM elements
• Minimize the number of iframes
• No 404s
• Reduce cookie size
• Optimize CSS sprites
• Don't scale images in HTML
• Make favicon.ico small and cacheable
Similarly, Google's PageSpeed recommendations, except those that have been specifically modified in this article, can apply to mobile. These tools from Yahoo! and Google should be the first line of defense against a slow site.
Let's spend a moment on how to measure performance. One technique already referenced is using adb to connect to Chrome running on your mobile device. This enables you to apply the full set of Web development tools in Chrome to the instance running on your phone. For interactive debugging, this can't be beat. It is worth spending some time to understand the Network, Timeline, Profile, and Resources screen so you can master debugging and optimizing using Chrome. Since Chrome and Mobile Safari are very similar rendering engines, this will pay dividends on both major mobile platforms.
For the long run, don't forget to implement
For AJAX, it's generally valuable to build a generic AJAX fetch layer that knows how to cache AJAX requests persistently. For example, a simple technique for a news or discussion board site would be to use unique hashes for each piece of content and a generic AJAX fetch layer that records all incoming data in an LRU (least recently used) cache in local storage. This general pattern of unique URLs and a
For the final bit of polish, it is worth thinking hard about using CSS tricks to
For the ultimate fit and finish, the site should never let the browser paint elements in an order of its choosing, but instead use layers of divs that are revealed in the right order and only when completely rendered. For transition durations, values of
A final note to consider is whether to use any application meta tags to give your Web site a special icon on the desktop, a splash screen, or to load full screen. For some sites these little touches add significantly to the fit and finish. The main drawback of these methods is that on iOS the Webview used for
On iOS, Mobile Safari gets special treatment and can start up significantly faster than a
With diligent attention to existing desktop recommendations and a few additions that take into account mobile network and CPU speed challenges, it's possible to create very fast, very slick Web site experiences for users. If you can't follow all the recommendations, this article has presented the most valuable techniques
One of the great pleasures of working at Google has been the opportunity to work with a wide array of really smart people. Almost every idea in this article is not mine, but rather the ideas of many teammates working on mobile Web sites over the years. They are Matthew Bolohan, Bikin Chiu, Ryan Fioravanti, Andrew Grieve, Alex Kennberg, Pavel Kobyakov, Robert Kroeger, Peter Mayo, Joanne McKinley, Derek Phillips, Keith Stanger, Neil Thomas, and Ilia Tulchinsky.
1. Cisco. 2013. Cisco Visual Networking Index: global mobile data traffic forecast update,
2. Fioravanti, R. 2012. Building
3. Google Code Blog. 2009. Gmail for Mobile HTML5 Series: reducing startup latency; http://googlecode.blogspot.ca/2009/09/gmail-for-mobile-html5-series-reducing.html.
4. Google Developers. 2012. Minimize
5. Google Developers. 2012. Web performance best practices; https://developers.google.com/speed/docs/best-practices/rules_intro.
6. Grove, R. 2010. Mobile browser cache limits, revisited; http://www.yuiblog.com/blog/2010/07/12/mobile-browser-cache-limits-revisited/.
7. Souders, S. 2010. Mobile cache file sizes; http://www.stevesouders.com/blog/2010/07/12/mobile-cache-file-sizes/.
8. Yahoo! Developer Network. 2013. Best practices for speeding up your Web site. http://developer.yahoo.com/performance/rules.html.
LOVE IT, HATE IT? LET US KNOW [email protected]
Alex Nicolaou joined Google in 2006, shortly after Google opened an office in Waterloo, Ontario, where his initial work was leading the development of Google's mobile apps including Gmail, Buzz, and YouTube among others. He is now leading a Chrome and ChromeOS effort focused on bringing ChromeOS to new devices. Until 2006, Nicolaou was president and a board member of aruna.ca Inc., a startup developing a unique RDBMS based on
© 2013 ACM
Originally published in Queue vol. 11, no. 6—
Comment on this article in the ACM Digital Library
Shylaja Nukala, Vivek Rau - Why SRE Documents Matter
SRE (site reliability engineering) is a job function, a mindset, and a set of engineering approaches for making web products and services run reliably. SREs operate at the intersection of software development and systems engineering to solve operational problems and engineer solutions to design, build, and run large-scale distributed systems scalably, reliably, and efficiently. A mature SRE team likely has well-defined bodies of documentation associated with many SRE functions.
Taylor Savage - Componentizing the Web
There is no task in software engineering today quite as herculean as web development. A typical specification for a web application might read: The app must work across a wide variety of browsers. It must run animations at 60 fps. It must be immediately responsive to touch. It must conform to a specific set of design principles and specs. It must work on just about every screen size imaginable, from TVs and 30-inch monitors to mobile phones and watch faces. It must be well-engineered and maintainable in the long term.
Arie van Deursen - Beyond Page Objects: Testing Web Applications with State Objects
End-to-end testing of Web applications typically involves tricky interactions with Web pages by means of a framework such as Selenium WebDriver. The recommended method for hiding such Web-page intricacies is to use page objects, but there are questions to answer first: Which page objects should you create when testing Web applications? What actions should you include in a page object? Which test scenarios should you specify, given your page objects?
Rich Harris - Dismantling the Barriers to Entry
A war is being waged in the world of web development. On one side is a vanguard of toolmakers and tool users, who thrive on the destruction of bad old ideas ("old," in this milieu, meaning anything that debuted on Hacker News more than a month ago) and raucous debates about transpilers and suchlike.