Optimizing JavaScript Loading

Optimizing javascript can be a bit tricky sometimes, but you can analyse the javascripts that are being used. We can categorize the javascripts into multiple segments such as 

  • Main thread JS
    • Critical JS – Typically JS that only affects above the fold elements of a page such as Hamburger menu click event, or any other button click to show popup, etc.
    • Asynchronous JS – The JS that a page needs on ready event or before onload event.
    • Defer JS – The JS that can be loaded onload that is after all the page content and assets are downloaded. 
  • Worker Thread JS – The JS that we can load lazily and run only on specific events or user interactions such as scroll, click, etc. 

In some cases, we just need to defer javascript so that it loads only after the page is loaded. To understand which JS you need first and which ones you need later, you can find out how your page looks with Javascript disabled in the browser.

If your web page shows all page elements with CSS properly then it means your page doesn’t need javascript to load on initial page rendering, and you can basically keep the main thread idle for other executions and interactions for users. This will reduce time to interactive and reduce total blocking time.

Here is how a web page gets rendered. As you can see in the above diagram, when a page request is made:

  • The network sends a response with HTML, which might take less than 100ms based on the server performance. 
  • After this DOM building process gets started. The CSS and JS files are requested, javascripts will be requested either asynchronously or synchronously. During this DOM building process, the main thread is blocked for any interactions. 
  • If these CSS and Javascript requests are more in number, that will add to blocking time. All this happens on the main thread. Hence we often get suggestions to reduce the main thread javascripts and eliminate render blocking resources. 
  • Once all CSS resources are collected and ready, the Build CSSOM process gets started. The time taken by this process will depend on the number of CSS files we have on the page. Inline CSS added on the page gets build really quickly as compared to the files requested using HTTP requests i.e. normal CSS stylesheet links.

This document describes the DOM Building Process very nicely and why Async or Defer javascript is important. 

Strategy to load Javascripts:

  1. First of all, analyse and measure the number of javascripts.
  2. Make a list of javascript files that are absolutely necessary to be loaded async while page loads and needed on document.ready or DOMContentLoaded event. We can call them “critical javascripts”. We can include only the javascripts which are required for above the fold content. Try to keep this to minimum as these will run on the main thread and keep the main thread busy. This will affect overall FID, and TTI.
  3. Make a list of javascript files that can be loaded later after everything is loaded. We can call them “non-critical javascripts”. These javascripts we should place in the footer of the page after all the textual or media content and add “defer” attribute to these scripts.
  4. Make a list of javascripts which are only needed when users try to interact with the pages such javascripts can be offloaded to worker thread so they don’t keep main thread busy and once user tries to interact with the page by the means of keypress, tap, click, or scroll, these javascripts can be sent back to main thread and loaded normally.

You can achieve this by using our plugin rt Scripts Optimizer, which will load the javascripts we specify using type=”text/rtscript” on worker thread, so that main thread only runs whatever is important before the DOM content loads fully. On user interaction it will basically load all the javascripts normally. So we can say we kind of lazy load javascripts loading, parsing and execution.