How to code faster, lighter JavaScript

null

Building interactive websites can involve sending JavaScript to your users. Often, too much of it. Have you been on a web page on your phone that looked like it had loaded, only to have nothing happen when you tapped a link or tried to scroll? We all have. 

Byte-for-byte, JavaScript is still the most expensive resource we send to mobile phones because it can delay interactivity in significant ways. In this feature we'll cover some strategies for delivering JavaScript efficiently to your users on mobile, while still giving them a valuable experience. On this page, we'll dig into exactly what's causing the problem. Jump to page 2 for some advice on exactly how to reduce your JavaScript load times, including some web design tools to help you monitor your sites effectively.  

Why is JS slowing your mobile sites down? 

When users access your site, you're probably sending down a lot of files, many of which are scripts. Perhaps you added a quick JavaScript library or plugin but didn't have a chance to check just how much code it was pulling in? It's happened to many of us. As much as I love JavaScript, it's always the most expensive part of your site. I'd like to explain why this can be a major issue.

Statistics from the HTTP Archive state of JavaScript report, July 2018

Statistics from the HTTP Archive state of JavaScript report, July 2018

Many popular sites ship megabytes of JavaScript to their mobile web users. The average web page today currently ship a little less – a median of about 350kB of minified and compressed JavaScript. Uncompressed, that bloats up to over 1MB of script a browser needs to process. Experiences that ship down this much JavaScript take more than 14 seconds to load and get interactive on mobile devices. 

A large factor of this is how long it takes to download code on a mobile network and then process it on a mobile CPU. Not only can that 350kB of script for a median site from earlier take a while to download, the reality is, if we look at popular sites, they actually ship down a lot more script than this. We're hitting this ceiling across both desktop and mobile web, where sites are sometimes shipping multiple megabytes of code that a browser then needs to process. The question to ask is: can you afford this much JavaScript?

Sites today will often send the following in their JavaScript bundles:

  • A suite of user-interface components (for example, code for widgets, carousels or drawers)
  • A client-side framework or user-interface library
  • Polyfills (often for modern browsers that don't need them)
  • Full libraries vs only what they use (for example, Moment.js and locales vs a smaller alternative like date-fns or Luxon)

This code adds up. The more there is, the longer it will take for a page to load.

Loading a modern web page

Click the icon in the top right to expand the image

Loading a web page is like a film strip that has three key moments: 

  • Is it happening? The moment you're able to deliver some content to the screen. Has the navigation started, has the server started responding?
  • Is it useful? The moment when you've painted text or content that enables the user to derive value from the experience and engage with it.
  • Is it usable? The moment when a user can start meaningfully interacting with the experience and have something happen.

I mentioned this term 'interactive' earlier but what does that mean? For a page to be interactive, it must be capable of responding quickly to user input. A small JavaScript payload can ensure this happens fast. Whether a user clicks on a link or scrolls through a page, they need to see that something is actually happening in response to their actions. An experience that can't deliver on this will frustrate your users. 

When a browser runs many of the events you're probably going to need, it's likely going to do it on the same thread that handles user input. This thread is called the main thread. Too much (main thread) JavaScript can delay interactivity for visible elements. This can be a challenge for many companies.

Why is JavaScript so expensive?

So why exactly is JavaScript causing these problems? A request is sent to a server, which then returns some HTML. The browser parses that markup and discovers the necessary code (CSS and JavaScript) and resources (images, fonts etc) composing it. Once complete, the browser has to download and process these files.

If we want to be fast at JavaScript, we have to download it and process it quickly. That means we have to be fast at the network transmission and the parsing, compiling and execution of our scripts. If you spend a long time parsing and compiling script in a JavaScript engine, that delays how soon a user can interact with your experience. 

Click the icon in the top right to enlarge

Keep in mind that resources on the web have different costs. A 200kB script has a different set of costs to a 200kB JPG. They might take the same amount of time to download but when it comes to processing the costs aren't the same. 

A JPEG image needs to be decoded, rasterised and painted on the screen. This can usually be done quickly. A JavaScript bundle needs to be downloaded and then parsed, compiled and executed. This can take longer than you might think on mobile hardware.

What is a good target for interactivity?

We on the Chrome team feel your baseline should be getting interactive in under five seconds on a slow 3G or 4G connection on a median mobile device. You might say: 'My users are all on fast networks and high-end phones!' But are they? You may be on 'fast' coffee-shop Wi-Fi but effectively only getting 2G or 3G speeds. Variability matters.

Click the icon in the top right to expand the image

Mobile is a spectrum composed of low-end, median and high-end devices. If we're fortunate, we may have a high-end phone, but the reality is that not all users will have those devices.

They may be on a low-end or median phone and the disparity between these multiple classes of devices can be stark due to thermal throttling, difference in cache sizes, CPU, GPU – you can end up experiencing different processing times for resources like JavaScript, depending on the device you're using. Your users on low-end phones may even be in the US

Some users won't be on a fast network or have the latest and greatest phone, so it's vital that we start testing on real phones and networks. Fast devices and networks can actually sometimes be slow; variability can end up reducing the speed of absolutely everything. Test on a real phone or at least with mobile emulation. Developing with a slow baseline ensures everyone – both on fast and slow setups – benefits. 

Click the icon in the top right to expand the image

Checking your analytics to understand what devices your users are accessing your site with is a useful exercise. WebPageTest has a number of Moto G4 phones preconfigured under the Mobile profiles. This is valuable in case you're unable to purchase your own set of median-class hardware for testing. 

It's really important to know your audience. Not every site needs to perform well on 2G on a low-end phone. That said, aiming for a high level of performance across the entire spectrum ensures that every potential user accessing your site has a chance to load it up fast.

Next page: Top tips for coding faster, lighter JavaScript