One of the essential optimizations for loading speed and interactivity is to defer the loading of JavaScript. Let’s go deeper to understand the impact of a blocking script on loading times, the solutions for minimising the impact, and the pitfalls you want to avoid.
We’ll also take the opportunity to explain the details of the solution we’ve developed: a feature called DeferJS.

What is a blocking script and why does it slow down the loading of a web page

To display a page, the browser parses the HTML code to build the DOM. As soon as the parser encounters a JavaScript (JS) element, it interrupts the DOM construction, retrieves the script, executes it and then continues its analysis of the HTML code. Since the browser displays the elements of a page based on the information it discovers while reading the HTML file, the location of the JavaScript has a direct impact on the loading speed and user experience, and determines how the page will render. This is why it is blocking: its loading and execution interrupts the analysis of the HTML code.

We explained this process in a previous article, the principle is illustrated here :

Javascript Web Performance HTML Parsing

But why block the rendering of the page? Well, because until the JavaScript file is retrieved and parsed, the browser doesn't know what to do with it, and stops everything while waiting for instructions.

The code may contain on premise scripts or scripts from third parties. Be aware that in the second case, as the browser has to fetch the third party scripts from where they are located (on a remote server, a cache...), the time needed for loading is even longer, and your performance may be impacted.

In short, first or third party, JavaScript has an impact on the loading speed. But fortunately, there are solutions to limit the latency by telling the browser that it can execute the scripts later, instead of starting the retrieval and analysis as soon as it discovers them in the HTML code. Indeed, some scripts are not essential for the page rendering and can wait until the end of the loading to be executed. So let's take the opportunity to optimize the performance and the loading speed of your pages by choosing the right option!

Making a script “non-blocking” with Async and Defer attributes

The HTML code contains information that guides the browser, which can be oriented using additional instructions that direct its work.

The <script> tags that call JavaScript resources can thus be enhanced with the following attributes:

  • Async: to download the script while continuing to parse the HTML to build the DOM, and execute the script once it is available. This is a recommended option especially for third party scripts or scripts that do not impact other files, this attribute improves the UX but may block the HTML parsing at runtime;
  • Defer: this option allows the execution of the JavaScript only after the complete analysis of the HTML, respecting the execution order as defined in the HTML.

These two attributes allow to modify the behavior of the browser by telling it to execute the instructions in a different order than the HTML reading. We provide more details on these techniques in our article dedicated to Asynchronous JavaScript (reminding why it does not make scripts "free" in terms of web performance).

But then, how to defer the execution of JavaScript for all your pages, without spending an infinite amount of time rewriting all your code, while managing the dependencies between scripts? We have provided a feature that automates this task on the fly to save you time: DeferJS.

Smartly automate the rewriting of code to Defer script execution

As we’ve seen, to make a blocking script “non-blocking,” an essential point you have to take into account is the potential dependency between scripts. 

Indeed, the first scripts generally declare libraries (like JQuery) which will be used by the scripts included in the page or declared later.

For this reason, you can’t apply an async attribute (which doesn’t follow the HTML parsing order to execute the scripts) to them because that would mean risking the library not being ready when it’s supposed to perform.

And what about the Defer attribute? That could work because it allows you to keep the script execution order, but… only on the condition that it applies to all scripts and that no script built into the page has dependencies with libraries. This is a very rare case—you’d be better off looking for a needle in a haystack.

Given these clarifications, you can understand why it’s difficult to systematically use the Async and Defer attributes, since they don’t account for the cases where scripts change the DOM in the declared location (via document.write).

So, now let’s talk about our favourite subject: smart automation of web performance optimizations!

You can get around the limitations of async and defer by orchestrating the execution of JS, and that’s exactly what DeferJS does.

In practical terms, here’s how DeferJS works:

  • The blocking scripts are only executed at the time of DOMContentLoaded to reproduce the behaviour of the Defer attribute and not block the initial rendering of the page.
  • The deferred scripts can write in the DOM at the location provided for in the document.write instructions. They can then correctly make calls to the DOM by simulating a partially built DOM up to the script node (even if the DOM is only really constructed at the time of execution).

As an orchestrator, DeferJS takes into account any declarations of the Async and Defer attributes present in the <script> tag to maintain loading properties as provided for in the code.

Did you know?

As a key feature of our platform, DeferJS is automatically active as soon as the SmartCache is set up. Thanks to the fact that DeferJS times the execution of JavaScript, the SmartCache can add the dynamic fragments of HTML retrieved from the origin. In other words, the system does teamwork.

 

So, what happens in the HTML file? The src attributes of the <script> elements are transformed into frz_orig_src and the engine adds a new type of attribute whose value is defined as text/frzjs. A window.onload manager is added to the HTML, which then execute all of the deferred scripts.

defer-javascript-web-perfomance

Script before and after being optimized with DeferJS feature

And that’s not all! We also add a pre-loading link to each deferred script to ensure they load as fast as possible. That compensates for the fact that the pre-scanned HTML can’t discover the URL of the scripts before knowing the attributes.

Proper usage of DeferJS

In what situations is DeferJS most useful? Mainly for scripts that have an impact on the interactivity of the page. 

Are there situations where it’s better to avoid deferring the scripts? Yes!

It’s worth noting that for A/B testing scripts that may greatly modify the DOM and for scripts managing carousels or the lazy-loading of images, deferring would only delay complete display of the page. 

That’s why this feature allows for precise settings so that you can isolate scripts critical for page rendering and choose tags to be excluded from processing.

Like all of our features, DeferJS is continuously improved to help you better manage your third party scripts and have  better and better responsive pages.

 

Curious about our features to improve your loading speed and user experience?
Find here all the reasons to automate your frontend optimization:
up to +40% conversions rates and +25% of SEO traffic ... and many more :

 

Why to use Fasterize?


Hello SMX Paris !