NL EN
JavaScript: the main culprit of slow websites
Tim van Schie
Tim van Schie
 7 Minutes
 Frontend

JavaScript: the main culprit of slow websites

JavaScript is like salt in a meal: it enriches the experience. But add too much and you'll spoil the taste. Likewise, loading a lot of JavaScript at once has a negative effect on the speed of a website, and therefore on the user experience. In our third article on website performance, we explain why in an understandable way. Afterwards, we share our own experiences in improving speed with regard to JavaScript.

JavaScript processing

Especially with mobile use, too much JavaScript is a disadvantage. The average smartphone has much more trouble processing this than a laptop or PC. And as a result, it often takes longer on a smartphone before interaction can take place on the page.  

In order to process JavaScript, a browser must go through four steps:  

  1. Download
    The browser must first download the JavaScript file. How long this takes depends on the speed of the internet connection. On a mobile 3G or 4G network this download takes longer than with a fast WiFi or LAN connection.

    Once a JavaScript file has been downloaded, the file is saved in the browser cache. This means that the browser does not need to download it again for subsequent page visits. That does not make the speed of this first step any less important. The ranking of a page in search engines depends partly on the speed of the site according to Google PageSpeed Insights. And Google always takes the first visit as a starting point, when the JavaScript still needs to be downloaded. 
  2. Unpacking
    To reduce the size of JavaScript files, it is common to ‘pack’ them on the server. The browser then needs to download less information. The files are then compressed. The packed file has to be unpacked again: decompressed. The browser does this immediately after downloading.

    In this respect, JavaScript is not very different from other file types. These also need to be downloaded and unpacked. The difference is in the following two steps, which we describe below. These activities are unique to JavaScript processing and ensure that 100 kB of unpacked JavaScript has a greater impact than, for example, a 100 kB image.
  3. Parsing/compiling
    After unpacking the file, the browser translates the JavaScript code. This is analysed, cut up into smaller parts and processed into computer code as much as possible. This code can be executed more quickly than the JavaScript readable by humans. This is called parsing and compiling. It is a complex process that requires a lot from the computer processor (CPU).

    And the difference between devices is mainly in the CPU: high-end laptops, PCs and smartphones have a more powerful processor than the average smartphone. This average smartphone takes about two to five times as long to parse and compile the JavaScript code as the fastest smartphone. This easily results in a loading time of several seconds. See the diagram from 2017 below for an illustration of this.
    https://medium.com/dev-channel/the-cost-of-javascript-84009f51e99e
     On the high-end iPhone 8 it takes just ~4s to parse/compile CNN's JS compared to ~13s for an average phone (Moto G4). This can significantly impact how quickly a user can fully interact with this site. Addy Osmani in 2017 about CNN.com - https://medium.com/dev-channel/the-cost-of-javascript-84009f51e99e
  4. Implementation
    After parsing and compiling, the JavaScript code can be executed on the page. This again takes more time on devices with a less powerful CPU.  

While performing steps 3 and 4, the browser is not able to do other things on the so-called main thread, the browser’s main road as it were. Executing JavaScript therefore blocks other things. That's why interaction on a page is only possible after the JavaScript has been processed.

Why mobile use is important 

On mobile in particular, where usage is generally faster and shorter than on a desktop, a user has to wait longer to load the page. That’s why mobile users are flocking to closed apps for a better experience. A negative development if you ask us, because it goes against the open and always available nature of the web. 

Only 10 to 15 percent of mobile usage takes place in a browser. On desktops this is no less than 50 percent (see this presentation by Alex Russel at Fronteers 2019). Just think of all the applications you can use in the browser, such as e-mail, social media, video platforms, word processing, chats and other (work-related) software. On mobile, web applications have never been able to make this leap to the browser. 

Because the difference between mobile and desktop is so significant, Google takes an average smartphone as a starting point when testing the speed of a website. In addition, there is a good chance that a mobile score of under 40 will have a negative influence on your position in the search results.  

Our experience with better JavaScript loading

We started working on improving the speed of the websites of several clients. Below we provide some examples of significant speed gains thanks to JavaScript modifications.  

Delete unnecessary JavaScript

The most logical first step is to remove unnecessarily loaded JavaScript. For one of our clients we were able to remove an old JavaScript library that was no longer in use. That was an easy gain of about 100 kB of JavaScript, which otherwise went through the above-mentioned processing steps unnecessarily. For another client, custom code was sent to the browser for two widgets that were no longer in use. Removing this widget code yielded savings of dozens of kBs.  

We also came across sloppiness in the use of the jQuery-library. This is a set of standard functionalities that you can use in other code to work more quickly. This same library was loaded up to three times by one of our clients. This had never been noticed before, because JavaScript does not report an error message for this. Here too it was easy to achieve gains.  

No or smaller version of JavaScript library

A JavaScript library can have added value, but it doesn’t always. Sometimes only part of the library is in use. And nowadays you can often achieve the same result without libraries and with little extra effort. That's why it's definitely worth considering rewriting your code and removing the library.  

Does rewriting require too much work? In that case, if your library supports this feature, consider loading only part of the library. This can for example be done using jQuery UI, an extension to the aforementioned jQuery-library. This extension offers the possibility to download and use only a small part. We were able to implement this for one of our clients and that made a big difference. 

Lightweight libraries 

Another option is the use of lightweight alternatives for libraries. For example, for the jQuery code there is the much smaller Zepto.js with largely the same jQuery functions. This library is often easy to use and takes up only 26 kB, while the jQuery-library takes up no less than 86 kB.   

Another example is Preact, a lightweight version of the React-library. We have now used it twice; both times successfully and almost without having to change anything in the original React code. For one client this resulted in a decrease from 452 to 292 kB (unpacked, see step 2 above). That’s a lot of savings in just three hours of work. 

Block as little as possible 

As described above, JavaScript blocks other things on the browser's main thread during execution. That’s why it’s important that the content has been styled as much as possible before the browser starts processing the JavaScript. For several projects, we were able to make major improvements by loading the JavaScript files in a non-blocking way. The best way is often through a defer attribute on the script tags, but a good second option is to place the script tags at the very bottom of the HTML code. 

Only load when necessary

Often, all of a website’s JavaScript is bundled into one file. The disadvantage of this is that a lot of code is probably loaded and processed unnecessarily. Think of the JavaScript code for a widget that the visitor never sees on his screen. For our clients, we therefore try to load defined pieces of JavaScript code only when they are needed. So not in one big bundle, but cut up where possible. For example, a separate bundle for a widget or the ‘My environment', which is only loaded on the required pages.  

Some of our new projects, such as for shign.com, are fully set up for this. With tools such as Webpack and Gatsbyjs, we serve JavaScript in small portions. Each block or component then has its own piece of JavaScript. Because of lazy loading, that part is only loaded when it is (almost) in the frame. For example, the code for a widget at the very bottom of the page does not need to be loaded if the user does not scroll that far down. In this way, the browser is minimally burdened with downloading and processing JavaScript. And that results in much faster pages. 

Execute only when necessary

But even if it is no longer easy to cut the JavaScript into smaller files, it may be worthwhile to only execute JavaScript code when the corresponding component appears on the screen. We were able to lazy load a React component for one of our clients, which resulted in significant performance gains. That JavaScript code performed API calls itself and loaded several images. Because of our improvement, this will only happen when the component appears on the screen. 

This article hopefully gives you a good idea of how JavaScript affects the speed of your website. Now you know how to influence the performance of your website by loading less and better JavaScript code. And how to ensure a better user experience on mobile and score higher in Google search results. In the next article in this series, we’ll discuss our experiences with performance improvement by loading images faster and smarter

Do you have questions about smarter use of JavaScript? Get in touch, we'll be happy to help. 

  • performance
  • javascript
Tim van Schie
Tim van Schie

Tim van Schie is a front-end developer at Aviva Solutions. He writes accessible HTML, CSS and JavaScript and works on interaction design. A real team player who, preferably using Agile methodology, shares new ideas and develops rich user experiences.