.mjs requests), going up to 59 resources at the 90th percentile.
When loading a website, the browser renders the HTML and requests the appropriate resources. It consumes the polyfills referenced in the code for the effective rendering and functioning of the page. Modern browsers that support newer syntax like arrow functions and async functions do not need loads of polyfills to make things work and therefore, should not have to.
This is when differential loading takes care of things. Specifying the
type="module" attribute would serve the modern browsers the bundle with modern syntax and fewer polyfills, if any. Similarly, older browsers that lack support for modules will be served the bundle with required polyfills and transpiled code syntax with the
type="nomodule" attribute. Read more about the usage of module/nomodule.
Let’s look at the data to understand the adoption of these attributes.
4.6% of desktop pages use the
type="module" attribute, whereas only 3.9% of mobile pages use
type="nomodule". This could be due to the fact that the mobile dataset being much larger contains more “long-tail” websites that might not be using the latest features.
defer attributes load the scripts asynchronously. The scripts with the
async attribute are executed irrespective of the order in which they are defined, however,
There was an anti-pattern observed in last year’s results that some websites use both
defer attributes on the same script, which falls back to
async if the browser supports it and using
defer for IE 8 and IE 9 browsers. This is, however, unnecessary now for most of the sites since
async takes precedence on all supported browsers and. In turn, this pattern interrupts HTML parsing instead of deferring until the page has loaded. The usage was so frequent that 11.4% of mobile pages were seen with at least one script with
defer attributes used together. The root causes were found and an action item was also taken down to remove such usage going forward.
This year, we found that 35.6% of mobile pages use the
defer attributes together. The large discrepancy from last year is due to a methodological improvement to measure attribute usage at runtime, rather than parsing the static contents of the initial HTML. This difference shows that many pages update these attributes dynamically after the document has already been loaded. For example, one website was found to include the following script:
So, what is Piwik? According to its Wikipedia entry:
This information strongly suggests that much of the increase we observed may be due to similar marketing and analytics providers that dynamically inject these
defer scripts into the page later than had been previously detected.
Even though a large percentage of pages use this anti-pattern, it turns out that only 2.6% of all scripts use both
defer on the same script element.
First-party vs third-party
The median mobile page requests 10 third-party resources and 9 first-party requests. This difference increases as we move up to the 90th percentile as 33 requests on mobile pages are first-party but the number goes up to 34 for third-party requests for the mobile pages. Clearly, the number of third-party resources requested is always one step ahead of the first-party ones.
The median desktop page requests 11 third-party resources, compared to 10 first-party requests. Irrespective of the performance and reliability risks that third-party resources may bring, both desktop and mobile pages consistently seem to favor third-party scripts. This effect could be due to the useful interactivity features that third-party scripts give to the web.
Nevertheless, site owners must ensure that their third-party scripts are loaded performantly. Harry Roberts advocates for going a step further and stress testing third-parties for performance and resilience.
As a page is rendered, the browser downloads the given resources and prioritizes the download of some resources the browser uses over others using resource hints. The
preload hint tells the browser to download the resource with a higher priority as it will be required on the current page. The
prefetch hint, however, tells the browser that the resource could be required after some time (useful for future navigation) and it’d better to fetch it when the browser has the capacity to do so and make it available as soon as it is required. Learn more about how these features are used in the Resource Hints chapter.
It would also be useful to see how many
prefetch hints are used per page, as that affects the impact of these hints. For example, if there are five resources to be loaded on the render and all five use the
preload hint, the browser would try to prioritize every resource, which would effectively work as if no
preload hint was used at all.
While the median number of
preload hints per mobile page has stayed the same, the number of
prefetch hints has decreased from three to two per page. Note that at the median, these results are identical for both mobile and desktop pages.
almanac.js script loaded on this page is 28 KB, but only 9 KB over the wire thanks to compression. You can learn more about the ways resources are compressed across the web in the Compression chapter.
To help explain this change, we analyzed the compression methods of first and third-party resources.
59.1% of third-party scripts on mobile pages are gzipped and 29.6% are compressed with Brotli. Looking at first-party scripts, these are 51.7% with Gzip compression but only 32.0% with Brotli. There are still 11.3% of third-party scripts that do not have any compression method defined.
To understand the reason for the worse scores this year, let’s dive deeper to look at how many bytes per page are unminified.
Only 0.1% of mobile pages use the
SourceMap response header on script resources. One reason for this extremely small percentage could be that not many sites choose to put their original source code in production through the source map.
98.0% of the
Libraries and frameworks
To understand the usage of libraries and frameworks, HTTP Archive uses Wappalyzer to detect the technologies used on a page.
jQuery remains the most popular library, used by a staggering 84% of mobile pages. React usage has jumped from 4% to 8% since last year, which is a significant increase. React’s increase may be partially due to recent detection improvements to Wappalyzer, and may not necessarily reflect the actual change in adoption. It’s also worth noting that Isotope, which uses jQuery, is found on 7% of pages, leading to RequireJS falling out of the top spots on just 2% of pages.
The most popular version of jQuery is 3.5.1, which is used by 21.3% of mobile pages. The next most popular version of jQuery is 1.12.4, at 14.4% of mobile pages. The leap to version 3.0 can be explained by a change to WordPress core in 2020, which upgraded the default version of jQuery from 1.12.4 to 3.5.1.
Libraries used together
Now let’s look at how the popular frameworks and libraries are used together on the same page.
|Frameworks and libraries||Desktop||Mobile|
|jQuery, jQuery Migrate||8.4%||8.7%|
|jQuery, jQuery UI||4.0%||3.7%|
|jQuery, jQuery Migrate, jQuery UI||2.6%||2.5%|
|React, jQuery, jQuery Migrate||0.9%||0.9%|
|Modernizr, jQuery, jQuery Migrate||0.8%||0.9%|
|Library or framework||Percent of pages|
With multiple ways to send and receive data on the web, let’s look at how many asynchronous requests are sent per page.
The median mobile page makes 4 asynchronous requests. If we look at the long tail, the largest number of asynchronous requests on desktop pages is 623, which is eclipsed by the biggest mobile page, which makes 867 asynchronous requests!
An alternative to the asynchronous AJAX requests are the synchronous requests. Rather than passing a request to a callback, they block the main thread until the request completes.
However, this practice is discouraged due to the potential for poor performance and user experiences, and many browsers already warn about such usage. It would be intriguing to see how many pages still use synchronous AJAX requests.
2.5% of mobile pages use the deprecated synchronous AJAX requests. To put this into perspective, let’s look at the trend by comparing the results with the last two years.
We see that there is a clear increase in the usage of asynchronous AJAX requests. However, there isn’t a significant decline in the usage of synchronous AJAX requests.
Knowing the number of AJAX requests per page now, we’d also be interested in knowing the most commonly used APIs to request the data from the server.
We can broadly classify these AJAX requests into three different APIs and dig in to see how they’re used. The core APIs
Beacon are used commonly across websites with XHR being used primarily, however
Fetch is gaining popularity and growing rapidly while
Beacon has low usage.
The median mobile page makes 2 XHR requests, but at 90th percentile, makes 6 XHR requests.
In the case of the usage of the
Fetch API, the median mobile page makes 2 requests, and in the long tail, reaches 3 requests. This API is becoming the standard XHR way of making requests, due in part to its cleaner approach and less boilerplate code. There may also be performance benefits to
Fetch over the traditional XHR approach, due to the way browsers can decode large JSON payloads off the main thread.
Beacon usage is almost non-existent, with 0 requests per page until the 90th percentile, at which there’s only one request per page. One possible explanation for this low adoption could be that
Beacon is typically used for sending analytics data, especially when one wants to ensure that the request is sent even if the page might unload soon. This is, however, not guaranteed when using XHR. A good experiment for the future would be to see if some statistics could be collected around any pages using XHR for analytics data, session data, etc.
It would be interesting to also compare the adoption of XHR and
Fetch over time.
Fetch and XHR, the usage has increased significantly over the years.
Fetch usage on mobile pages is up 4 points and XHR is up 19 points. The gradual increase of
Fetch adoption seems to point towards a trend of cleaner requests and better response handling.
Web Components and the shadow DOM
With the web becoming componentized, a developer building a single page application may think about a user view as a set of components. This is not only for the sake of developers building dedicated components for each feature, but also to maximize component reusability. It could be in the same app on a different view or in a completely different application. Such use cases lead to the usage of custom elements and web components in applications.
Custom Elements are customized elements built on top of the
HTMLElement API. Browsers provide a
customElements API that allows developers to define an element and register it with the browser as a custom element.
3.0% of mobile pages use custom elements for one or more parts of the web page.
Shadow DOM allows you to create a dedicated subtree in the DOM for the custom element introduced to the browser. It ensures the styles and nodes inside the element are not accessible outside the element.
0.4% of mobile pages use shadow DOM specification of web components to ensure a scoped subtree for the element.
template element is very useful when there is a pattern in the markup which could be reused. The contents of
Fewer than 0.1% of web pages have adopted the use of templates. Although templates are well supported in browsers, there is still a very low percentage of pages using them.
We saw how so many features that improve rendering and resource loading performance could be more widely utilized to provide users with faster experiences. As a developer, you can start by adopting these new web platform features. However, make sure to use them wisely and ensure that they actually improve performance, as some APIs can cause harm through misuse, as we saw with
defer attributes on the same script.
Making appropriate use of the powerful APIs that we now have access to is what it will take to see these numbers improve further in the coming years. Let’s continue to do so.