Sync, async and defer
In a blog post published on Web Performance Calendar in 2016, Steve Souders breaks down these three attributes and explains why he prefers defer over async – even though, while neither blocks the HTML parser, they can block page rendering. This is how each method works:
Putting each component under the magnifying glass, this article details how a webpage is built from the ground up and explains why certain scripts are blocked by the HTML parser.
As an example, this method is used for A/B test scripts in order to avoid flickering.
Async is widely considered to be non-blocking. As we shall see, this isn’t entirely true!
In the case of asynchronous JS, the browser does not interrupt the parsing of the HTML code, it downloads the script in parallel. Once the download is complete, however, it executes the script immediately and blocks the parsing of the remaining HTML code, the execution of the other scripts and the rendering of the page.
With the defer attribute, the browser identifies and then downloads the script, but will only execute it once all of the HTML code has been parsed. In this case, the script execution order is preserved and initiated after the DOM Interactive.
Asynchronous JS, or the temptation to stack up scripts
On account of its (misleading) reputation as non-blocking, the async attribute has proliferated all over the web, to the point that one could well forget that a browser has only the one main thread to handle HTML parsing, CSS, JS execution and page rendering – not to mention any downloads in the background.
This phenomenon has also been exacerbated by the fact that server response and connection times are progressively improving, yet this is no reason to use an async attribute to increase the number of scripts ad infinitum. There is a price to pay in web performance!
When a large number of asynchronous scripts execute, although it does not block downloading, it does block execution. Addy Osmani provides a perfect illustration of this principle in this table of script priorities in Chrome: the asynchronous scripts have a low loading priority, despite having a high execution priority.
It’s time we set the record straight and disambiguated what is really meant by “non-blocking”: this label only holds true for the network stack – not for page rendering or interactivity.
Just the one asynchronous script can result in a SPOF, not in the rendering but in the execution, which undermines the interactivity of a webpage. In the case of a third-party script, there is nothing you can do to change this.
As we are highly attuned to the benefits of scripts – all the more so for marketing – allow us to share some best practices to help you use them without compromising performance:
- Break down your code to eliminate long tasks (scripts that take more than 50 ms to execute) which block the browser and raise your Time to Interactive to the detriment of your UX.
- Set yourself a performance budget and do the necessary housekeeping with regard to redundant scripts.
- Don’t rely exclusively on a tag manager, since these have no bearing on script execution.
Optimise, automate and sustain your web performance: