Skip to main content

Web Performance

Introduction

Consumers nowadays heavily rely on the web to access digital content and services, and web performance plays a crucial role for these online ventures to success.

Studies have pointed out that fluent and quickly responsive website provides a better user experience and retains users better than websites that are sluggish, which further contriubtes to increase in visit rate and business outcomes.

Measuring performacne

To properly measure the performance, Google has defined an user-centric metrics called Web Vitals, including multiple crucial indicators to provide a standard to measure performance of a website. Refer to Web Vitals note for detail.

Train of Thoughts

When users attempt to visit a website, the browser sends an initial HTTP GET request on users behalf to the web server to request for contents to display, which is often a html file. While parsing the html, additional request can be made to fetch resources such as image, script, CSS, embedded iframe, etc.

This leads to our first performance goal: resources must be returned and loaded as quickly as possible. This include approaches such as:

  • Optimize server performace
  • Utilize cache (CDN, browser cache, local storage...)
  • Reduce blocking time when parsing and loading Javascript/CSS file
  • Asset optimization such as resource lossy(e.g jpeg) and lossless compression(e.g gzip/brotli), minify/uglify with bundler, preload and responsive images, art direction etc.

Performance Analyzing Tools

Resource Hinting

To build an https connection to fetch resources, multiple steps, such as DNS lookup, connection establishing, encyyting connections, are conducted and each requires a request round trip which causes delay for actual response. With resource hinting, some steps can be pre-executed to provided a shorter response delay.

Resource hints, however, get their name because they are not mandatory instructions. They provide the information about what you'd like to happen, but it's ultimately up to the browser to decide whether to execute them.

preconnect

When connecting to a cross-origin server is expected in a near future, adding a preconnect resource hint can inform the browser to build the connection as soon as possible.

With preconnect, connections can be built in advance instead of when the cross-origin resource is encountered when parsing. It is useful for pages that have large external resources. It is useful for fetching resources from CDN (e.g for fonts/images/scripts...), where you know the domain to fetch resource from but not the exact resource URI.

A crossorigin attribute is added to indicate that a resource must be fetched using Cross-Origin Resource Sharing (CORS). If omitted, the browser opens a new connection when it downloads the resource and doesn't reuse the connection opened with the preconnect hints, but simply peforms a DNS lookup

<head>
<link rel="preconnect" href="https://example.com">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
</head>

A preconnect can also be built with the Link http header:

Link: <uri-reference>; param1=value1; param2="value2"
tip

However, pre-establishing too much connection to cross-origin servers might not be reasonable. It isn't cost effective and browsers close connections that are not used within 10 seconds. One can either use preconnect for the most crucial resources only, or utilize dns-prefetch instead.

dns-prefetch

Compared to preconnection resource hint, dns-prefetch doesn't actually establish a connection to a cross-origin server, but rather just performs the DNS lookup for it ahead of time.

In particular, it may be a desirable resource hint to use in cases of links that navigate to other websites that you think the user is likely to follow.

Another usecase is to use the Intersection Observer API to inject dns-prefetch hints into the current page's HTML when links to other websites are scrolled into the user's viewport.

preload

The preload directive is used to initiate an early request for a resource required for rendering the page.

<link rel="preload" href="/lcp-image.jpg" as="image">

preload hint should be limited to late-discovered critical resources. The most common use cases are font files, CSS files fetched through @import declarations, or CSS background-image resources that are likely to be Largest Contentful Paint (LCP) candidates. This ensures the resources are available earlier and are less likely to block the page's render, improving performance.

tip
  1. Similarly to preconnect, the preload directive requires the crossorigin attribute if you are preloading a CORS resource—such as fonts. If you don't add the crossorigin attribute—or add it for non-CORS requests—then the resource is downloaded by the browser twice, wasting bandwidth that could have been better spent on other resources.
  2. A resource specified in a preload directive is downloaded twice if the as attribute is missing on the directive's <link> element.

prefetch

The prefetch directive is used to initiate a low priority request for a resource likely to be requested for future navigations.

<link rel="prefetch" href="/next-page.css" as="style">
s

Given the speculative nature of prefetch, its use comes with the potential downside that data used to fetch the resource may go unused if the user does not navigate to the page that ends up needing the prefetched resource.

Fetch priority API

When loading resources, some resources are quite expensive to fetch such that a browser tends to wait until the resource is actually needed will it make the actual request.

For instance, a image is large in transfer size and requires parsing its style through inline/css style to actually determine how and where to display it. Image resources can thus be given a low priority at first, but later considered as high priority once the browser computes the render tree and figure out the image is a hero image that greatly affects the LCP core Web Vital.

Fetch Priority API is thus introduced to allow using the fetchpriority attribute to explictly indicate the fetching priority of a resource. One can use the attribute with <link/>, <img/>, and <script/> elements.

Due to its explicity, this API can be treated as an complementary mechanism to the resource hint mechanism and be particularly useful for usecases such as:

  • Boosting the priority of the LCP image
  • Increasing the priority of async scripts (better semantics than inserting a <link rel="preload"/>for the async script)
  • Decreasing the priority of late-body scripts to allow for better sequencing with image
  • Lower the priority of above-the-fold images that are offscreen in an image carousel
  • Lower the priority of preloaded resources

While this API helps improve performance in specific usecases, there are some implementation details to be aware of.

Updating HTTP Protocol

Currently, the most used HTTP version is HTTP/1.x. However, this version of HTTP has below limitations:

With HTTP/2, performance has been improved greatly compared to HTTP/1.x by introducing below features:

  • Headers can be compressed
  • Resolve HOL blocking issue at HTTP level (NOT AT TCP LEVEL) with multiplexing
  • Weighted prioritization
  • Server push

Domain sharding

Web Worker

References