Introducing NoState Prefetch

Intro

NoState Prefetch is a new mechanism in Chrome that is an alternative to the deprecated
prerendering process, used to power features like <link rel="prerender">. Like prerendering, it fetches resources in advance; but unlike prerendering
it does not execute JavaScript or render any part of the page in advance. The goal of NoState
Prefetch is to use less memory than prerendering, while still reducing page load times.

NoState Prefetch is not an API but rather a mechanism used by Chrome to implement various APIs
and features. The Resource Hints API, as well as the
prefetching of pages by the Chrome address bar, are both
implemented using NoState Prefetch. If you’re using Chrome 63 or later, your browser is already
using NoState Prefetch for features like <link rel="prerender">.

This article explains how NoStatePrefetch works, the motivations for introducing it, and
instructions for using Chrome's histograms to view stats about its usage.

Motivation

There were two primary motivations for introducing NoState Prefetch:

Reduce memory usage

NoState Prefetch only uses ~45MiB of memory. Maintaining the preload scanner is the primary
memory expense for NoState Prefetch and this cost remains relatively constant across different
use cases. Increasing the size or volume of fetches does not have a significant effect on the
amount of memory consumed by NoState Prefetch.

By contrast, prerendering typically consumes 100MiB of memory and memory consumption is capped at
150MiB. This high memory consumption makes it unsuitable for low-end (i.e. <= 512MB of RAM)
devices. As a result, Chrome does not do prerendering on low-end devices and instead will
preconnect.

Facilitate support of new web platform features

With prerendering, no user-facing (e.g., playing music or video) or stateful actions (e.g.,
mutating session or local storage) should occur. However, it can be difficult and complex to
prevent these actions from occurring while rendering a page. NoState Prefetch only fetches
resources in advance: it does not execute code or render the page. This makes it simpler to
prevent user-facing and stateful actions from occurring.

Implementation

The following steps explain how NoState Prefetch works.

NoStatePrefetch is triggered.

A prerender resource hint (i.e. <link rel="prerender">) and some Chrome features will
trigger NoState Prefetch provided that the following two conditions are met: a) the user is
not on a low-end device, and b) the user is not on a cellular network.

A new, dedicated renderer is created for the NoState Prefetch.

In Chrome, a
“renderer”
is a process responsible for taking an HTML document, parsing it,
constructing its render tree, and painting the result to the screen. Each tab in Chrome, as
well as each NoState Prefetch process, has its own renderer to provide isolation. This
helps minimize the effects of something going wrong (e.g., a tab crashing) as well as
prevent malicious code from accessing other tabs or other parts of the system.

The resource that is being loaded with NoState Prefetch is fetched. The HTMLPreloadScanner
then scans this resource to discover any subresources that need to be fetched.

If the main resource or any of its subresources has a registered service worker, these requests will go through the appropriate service worker.

NoState Prefetch only supports the GET HTTP method; it will not fetch any subresources that
require the use of other HTTP methods. Additionally, it will not fetch any resources that
require user actions (e.g., auth popups, SSL client certificate, or manual overrides).

Subresources that are fetched will be fetched with an “IDLE” Net Priority.

The “IDLE” Net Priority is the lowest possible Net Priority in Chrome.

All resources retrieved by the NoState Prefetch are cached according to their cache headers.

NoState Prefetch will cache all resources except those with the no-store Cache-Control
header. A resource will be revalidated before use if there is a Vary response header,
no-cache Cache-Control header, or if the resource is more than 5 minutes old.

The renderer is killed after all subresources are loaded.

If subresources time out, the renderer will be killed after 30 seconds.

The browser does not make any state modifications besides updating the cookie store and the
local DNS cache.

It’s important to call this out because this is the “NoState” in “NoState Prefetch”.

At this point in the “normal” page load process, the browser would probably do things that
would modify the browser state: for example, executing JavaScript, mutating sessionStorage
or localStorage, playing music or videos, using the History API, or prompting the user. The
only state modifications that occur in NoState Prefetch are the updating of the DNS cache
when responses arrive and the updating of the cookie store if a response contains the
Set-Cookie header.

When the resource is needed, it is loaded into the browser window.

However, unlike a prerendered page, the page won't be immediately visible - it still needs
to be rendered by the browser. The browser will not reuse the renderer it used for the
NoState Prefetch and will instead use a new renderer. Not rendering the page in advance
reduces the memory consumption of NoStatePrefetch, but it also lessens the possible impact
it can have on page load times.

If the page has a service worker, this page load will go through the service worker again.

If NoState Prefetch has not finished fetching subresources by the time the page is needed,
the browser will continue with the page load process from where NoState Prefetch left off.
The browser will still need to fetch resources, but not as many as would be necessary if
NoState Prefetch had not been initiated.

Impact on Web Analytics

Pages loaded using NoState Prefetch are registered by web analytics tools at slightly different
times depending on whether the tool collects data on the client-side or the server-side.

Client-side analytics scripts register a pageview when the page is shown to the user. These
scripts rely on the execution of JavaScript and NoState Prefetch does not execute any JavaScript.

Server-side analytics tools register metrics when a request is handled. For resources loaded via
NoState Prefetch, there can be a significant gap of time between when a request is handled and when
the response is actually used by the client (if it is used at all). Since Chrome 69, NoState Prefetch
adds the header Purpose: Prefetch to all requests in order to make them distinguishable from
normal browsing.

Check it out

NoStatePrefetch shipped in December 2017 in Chrome 63. It's currently used to:

Implement the prerender resource hint

Fetch the first result in Google Search results

Fetch pages that the Chrome address bar predicts are likely to be visited next

You can use the Chrome Internals to see how you’ve been using NoStatePrefetch.

To view the list of sites that have been loaded with NoState Prefetch, go to
chrome://net-internals/#prerender.

To view stats on your NoState Prefetch usage, go to chrome://histograms and search for
“NoStatePrefetch”. There are three different NoState Prefetch histograms - one for each use case
of NoState Prefetch:

“NoStatePrefetch” (stats for usage by prerender resource hints)

“gws_NoStatePrefetch” (stats for usage by the Google search results page)

“omnibox_NoStatePrefetch” (stats for usage by the Chrome address bar)

rss_feed
Subscribe to our
RSS or
Atom feed
and get the latest updates in your favorite feed reader!