Web Performance 101

What’s even cooler is that browsers have a simple built-in way to do all these things. There’re five < Link rel> tags that instruct the browser to preload something:

<link rel="prefetch" href="/style.css" as="style" />
<link rel="preload" href="/style.css" as="style" />

<link rel="preconnect" href="https://example.com" />
<link rel="dns-prefetch" href="https://example.com" />

<link rel="prerender" href="https://example.com/about.html" />Copy the code

Here’s what they each of them does and when to use them.

Jump to: Preload prefetch preconnect DNS – Prefetch prerender

preload

<link rel="preload">

The browser doesn’t do anything with The resource after downloading it. Stylesheets aren’t applied. It’s just cached — so that when something else needs It, It’s available immediately.

Syntax

<link rel="preload" href="/style.css" as="style" />Copy the code

href points to the resource you want to download.

as can be anything you can download in a browser:

  • style for stylesheets,
  • script for scripts,
  • font for fonts,
  • fetch for resources downloaded with fetch() or XMLHttpRequest.
  • Other values – See the full list on MDN

as

When to use

Use it when you’ll need a resource soon.
<link rel="preload">

  • You use custom fonts. The @font-face rule that applies those fonts is in an external CSS file:
    <! -- index.html --> <link rel="stylesheet" href="index.css" />Copy the code
    /* index.css */
    @font-face {
      src: url('comic-sans.woff2') format('woff2');
    }Copy the code

    By default, comic-sans.woff2 will start downloading only when index.css is fetched and applied. Instead of waiting for it that long, use to initiate the download sooner:

    <link rel="preload" href="comic-sans.woff2" as="font" />Copy the code
  • You split your styles per the Critical CSS approach. With this approach, You’ll split your CSS into two parts — critical (required for immediate rendering) and non-critical:
    <style>
    /* Inlined critical styles */
    </style>
    
    <script>
    /* Custom JS that starts downloading non-critical styles */
    loadCSS('/app/non-critical.css');
    </script>Copy the code

    With this approach, non-critical styles will start downloading only when JavaScript starts executing – which can be a few seconds after the first render. Instead of waiting for JS to execute, use <link rel="preload"> to initiate the download sooner:

    <style>
    /* Inlined critical styles */
    </style>
    
    <link rel="preload" href="/app/non-critical.css" as="style" />
    
    <script>
    /* Custom JS that starts downloading non-critical styles */
    loadCSS('/app/non-critical.css');
    </script>Copy the code

Don ‘t overuse it.

Don’t use If you Don’t need a resource immediately after the page Loads. If you only need it later — e.g., for a next page — use

More details

It’s mandatory.
<link>
has
<link rel="preload">

Priorities. For different kinds of resources (styles, scripts, fonts, etc.), browsers typically assign different priorities. This allows for downloading the most important resources first. For a resource fetched with <link rel="preload">, browsers use the as attribute to determine its priority. For Chrome, see the full table of Chrome priorities for more details

2) How I find what to preload:





— Go to DevTools and run a performance recording of how the page loads


Scroll through the Network section and find stuff that blocks page rendering but gets too late (= too much Down in Network section). That’s usually CSS or JS





1/2
pic.twitter.com/5Uem9U34jc- Ivan Akulov (@ iamakulov)
January 2, 2019

prefetch

<link rel="prefetch">

The browser doesn’t do anything with The resource after downloading it. Stylesheets aren’t applied. It’s just cached — so that when something else needs It, It’s available immediately.

Syntax

<link rel="prefetch" href="/style.css" as="style" />Copy the code

href points to the resource you want to download.

as can be anything you can download in a browser:

  • style for stylesheets,
  • script for scripts,
  • font for fonts,
  • fetch for resources downloaded with fetch() or XMLHttpRequest.
  • Other values – See the full list on MDN

as

When to use

Use it for resources from other pages.
<link rel="prefetch">

  • You have an e-commerce site, and 40% of your users go from the home page to a product page. Use <link rel="prefetch"> to download CSS and JS files responsible for rendering product pages
  • You have a single-page app, and you code-split it so that different pages load different bundles. When a user visits some page, ask your router what other pages it links to, and use <link rel="prefetch"> to preload bundles for those pages

It’s probably safe to use it as much as you want.

Don’t use for urgent resources. Don’t use When you’ll need a resource in a few seconds case, use instead.

More details

Not mandatory.
not
<link rel="prefetch">

Priorities in Chrome. In Chrome, <link rel="prefetch"> downloads are usually prioritized with the lowest priority (full table of priorities). This means they are usually scheduled after everything else got loaded.

preconnect

<link rel="preconnect">

A browser has to set up a connection when it retrieves something from a new third-party domain. (A third-party domain is a domain that’s different from the one your app is hosted on.) This may happen when a site uses a font from Google Fonts, loads React from a CDN, or requests a JSON response from an API server.

Setting up a new connection takes several hundred milliseconds. It’s only needed once per domain, but it still takes time. If you set up a connection in advance, You’ll save that time and load resources from that domain faster.

Syntax

<link rel="preconnect" href="https://api.my-app.com" />Copy the code

href points to the domain name you want to resolve. Feel free to specify it with the scheme (https://domain.com) or without it (//domain.com), it would work the same.

When to use

Use it for domains you’ll need rapid spreading.
<link rel="preconnect" />

  • Your app is hosted at my-app.com, and it makes AJAX requests to api.my-app.comYou don’t know what specific requests You’ll be making to that domain — because You make them dynamically from JS

    Use <link rel="preconnect"> to connect to api.my-app.com in advance and make the first data request faster

  • Your app is hosted at my-app.com, and it uses Google Fonts. Google Fonts load fonts in two stages: first, a CSS file is downloaded from fonts.googleapis.com; then, that CSS file requests fonts from fonts.gstatic.com.

    You can’t know what specific font files from fonts.gstatic.com you’ll need until you download the CSS file from fonts.googleapis.com. Use <link rel="preconnect"> to set up a connection in advance

Use it to slightly speed up some third-party script or style.
<link rel="preconnect" />

Don’t overuse it. Setting up and keeping a connection open is costly — both for a client and a server. Use this tag for 4-6 domains at most.

More details

Not mandatory.
not
<link rel="preconnect">

What the connection process includes. To connect to each site, a browser has to perform the following steps:

  • DNS resolution. Find a server’s IP address (216.58.215.78) for a specified domain name (google.com)
  • TCP handshake. Perform a roundtrip (a message goes client → server → client) to initiate a TCP connection to a server
  • TLS handshake (only for HTTPS sites). Perform two roundtrips (a message goes client → server → client → server → client) to initiate a secure TLS session

improve and speed up the connection mechanism

dns-prefetch

<link rel="dns-prefetch">

A browser has to perform a DNS resolution when it connects to a new third-party domain. (A third-party domain is a domain that’s different from the one your app is hosted on.) This may happen when your site uses a font from Google Fonts, loads React from a CDN, or requests a JSON response from your API server.

For each new domain, resolving the DNS record usually takes around 20-120 ms. It only affects the first resource downloaded from that domain, but it still matters. If you perform a DNS resolution in advance, you’ll save that time and load that resource faster.

Syntax

<link rel="dns-prefetch" href="https://api.my-app.com" />Copy the code

href points to the domain name you want to resolve. Feel free to specify it with the scheme (https://domain.com) or without it (//domain.com), it would work the same.

When to use

Use it for domains you’ll need shortly. will help you when you have some important resources On third-party domains the browser doesn’t know about in advance. For example:

  • Your app is hosted at my-app.com, And it makes AJAX requests to api.my-app.com. The browser doesn’t know that you’ll be making requests to that domain — because you make them from JS.

    Use <link rel="dns-prefetch"> to resolve api.my-app.com and make the first data request faster

  • Your app is hosted at my-app.com, and it uses Google Fonts. Google Fonts load fonts in two stages: first, a CSS file is downloaded from fonts.googleapis.com; then, that CSS file requests fonts from fonts.gstatic.com.

    The browser doesn’t know that you’ll load fonts from fonts.gstatic.com, so use <link rel="dns-prefetch"> to resolve it in advance

Use it to slightly speed up some third-party script or style. If you have a third-party resource in the page that you really need to load sooner, add for that domain. It will instruct the browser to schedule DNS resolution for that domain sooner.

Note on and . Using both of these tags for the same domain is not already includes everything does, and more. However, it can still make sense in two cases:

  • You want to support older browsers. is supported starting from IE10 and Safari 5. has been supported in Chrome and Firefox for a while, but was added to Safari only in 11.1, And still isn’t supported in IE/Edge. If you need to support those browsers, use as a fallback for .

  • You want to speed up more than 4-6 domains. It’s not recommended to use with more than 4-6 domains domains, as opening and keeping a connection is an expensive operation. is more lightweight, so use it for other third-party domains if you want to speed them up too.

More details

Not mandatory. The browser is not required to follow a instruction. This means it can decide Not to perform the DNS resolve — e.g., if there’s already a lot of them, or in some other cases.

Each server on the Internet is addressed by a unique IP address which looks like 216.58.215.78. However, when you visit a site, You don’t type a server’s IP address – you use a site domain (like google.com). This works thanks to DNS (domain Name Servers – Servers that map a domain (google.com) to a server’s IP address (216.58.215.78).

To resolve a domain name, the browser has to perform a request to a DNS server. This is what takes those 20-120 ms when you connect to a new third-party domain.

DNS is cached, though not reliably. Some operating systems and browsers cache your DNS requests. This would save time if you need to Retrieve something from a third-party domain again — but don’t rely on it. Linux typically doesn’t have DNS caching at all. Chrome has a DNS cache, but it only lives for a minute. Windows caches DNS responses for 5 days.

prerender

asks the browser to load a URL and render it in an invisible tab. When a user clicks on a link to that URL, The page should be rendered immediately. It’s helpful when you’re really sure a user will visit a specific page next, and you want to render it faster.

Despite (or because of?) its power, in 2019, <link rel="prerender"> has bad support in major browsers. See More details for more.

Syntax

<link rel="prerender" href="https://my-app.com/pricing" />Copy the code

href points to the URL you want to render in the background.

When to use

If you have a conversion funnel where 70% of visitors go from, you are really sure a user will go to some page next page A to page B, in page A might help to render page B super-quickly.

Don’t overuse it. Pre-rendering a page is extremely costly — both in terms of traffic and memory. Don’t use for more than one page.

More details

Not mandatory. The browser is not required to follow a <link rel="prerender"> instruction. This means it can decide not to perform the prerender – e.g., if the memory is low, or the connection is slow.

Chrome doesn’t do a full render. Instead of a full render, Chrome makes a NoState Prefetch to save memory. This means Chrome downloads the page and all subsequent resources, but doesn’t render it or execute JavaScript.

Firefox and Safari don’t support this tag at all. This doesn’t break the specification, as browsers are not required to act on the tag; but this is still quite sad. Firefox has an implementation bug which has been open for 7 years; and there are reports that state Safari doesn’t support it too.

Summing up

Use:

  • <link rel="preload">— When you’ll need a resource in a few seconds
  • <link rel="prefetch">— When you’ll need a resource on a next page
  • <link rel="preconnect">— When you know you’ll need a resource soon, but you don’t know its full URL yet
  • <link rel="dns-prefetch">— Also when you know you’ll need a resource soon, but you don’t know its full URL yet (for older browsers)
  • <link rel="prerender">— When you’re certain users will navigate to a specific page, and you want to speed it up

This article was brought to you by PerfPerfPerf. We help companies to earn more by making web apps faster.

Have a web performance issue or just want to learn what to improve? We’d be glad to help