This content originally appeared on web.dev and was authored by Addy Osmani
Resource hints, such as preconnect
,
preload
,
prefetch
, and
prerender
, help
the browser figure out which resources will the user need in the near future.
preconnect
and preload
are declarative hints—the browser must act on
them, so use them when you are sure that a resource will be required during the
next load.
prefetch
and prerender
are speculative hints—use these to recommend that
the browser should fetch a certain resource because there's a high chance it
might be required.
This article focuses on speculative prefetching and prerendering. Learn more about how they're used, the drawbacks of the current implementations, and popular external libraries that implement sophisticated speculation. Enhancements that bring same-origin speculative prerendering to the browser are under developed and you can learn more about their design and participate in Chrome origin trial.
prefetch
and prerender
: Current implementation #
Users looking at a list of links relevant to their interest (for example, a list
of products or articles matching a search keyword or the user's preferences)
will likely click on the links at the top. If they navigate back to the list
page, they might click the following link in the list. prefetch
and prerender
rely on this knowledge of the user's behavior. Developers speculate which page
(B) is likely to be requested after a specific page (A).
prefetch
hint #
When developers include a prefetch
hint on page A to tell the browser that it
can fetch either page B or specific resources on page B in advance, the browser
can fetch those resources while it is idle without affecting the processing of
page A.
The syntax for using prefetch
in the origin page (page A of our example) is as
follows:
<link rel="prefetch" href="/results/" as="document">
The as
attribute here is optional but helps the browser set the correct
headers required to determine if the resource is already in the cache.
The available support for prefetch
and
implementation options have matured slightly over the last couple of years.
prerender
hint #
Including a prerender
hint tells the browser to render page B in advance.
Prerendering a page enables an instant navigation experience when the user
actually clicks on the link for page B.
The syntax for using prerender
in the origin page is as follows:
<link rel="prerender" href="/next-page/">
prerender
behavior, however, is still not clearly defined or universally
implemented.
Prefetch implementation #
There are a few important points to note about prefetch behavior (especially in Chrome):
- You can prefetch either the next page entirely or same-origin subresources such as stylesheets or scripts that would be required by the next page.
- The prefetched resources are stored in the HTTP Cache if they are cacheable.
- Chrome keeps the cached items for 5 minutes.
- When the resources are requested or required they are retrieved from the cache. However, if they have not finished loading the partially loaded resource is picked up by Chrome to continue loading it.
- Prefetching of resources consumes extra bytes and is not recommended if a user has data-saver mode enabled. The connection type and other details about users' data preferences can be determined via the Network Information API.
Prerender implementation using no-state prefetch #
The
original implementation
for the prerender
hint in Chromium was using a lot of memory so it was
deprecated in favour of a
no-state prefetch
which fetches resources in advance but it does not execute JavaScript or render
any part of the page in advance. Originally prerender consumed around 100 MiB of
memory and could potentially disrupt UI when certain components like media were
prerendered.
The current implementation using a no-state prefetch consumes significantly
lower memory of around 45 MiB, while still reducing page load times. The fetch
is triggered by a link element with a prerender
resource hint. The no-fetch
prefetch is carried out in a new dedicated
renderer
that is isolated from the visible tabs and cannot disrupt UI. The no-state
prefetch process caches the resources required but does not render them. It also
does not modify the state of the browser except when updating the DNS cache and
the cookie store. The new renderer is killed after all subresources are loaded.
A new renderer is created to render the page when the user requests it.
With a no-state prefetch implementation for prerender, the goal of instant page loads still eludes us. Before exploring how we can achieve instant page loads, let's take a look at some out-of-the-box options that implement speculation logic for prefetch which may also be relevant to the prerender implementation.
Smart speculation with third-party libraries #
Developers have insight into how people use their site and use that knowledge to decide what should be prefetched or prerendered. These usage trends tend to evolve over time, so developers need to update their resource hints based on the latest analytics data available for the site.
There are also libraries such as quicklink and guess.js, that use heuristics to determine which resources should be prefetched at runtime. With these, developers don't need to guess what should be prefetched. The libraries take the decision based on available data.
Quicklink #
Quicklink uses Intersection Observer API to determine which links are in the viewport and prefetches them when the browser is idle if the user is not on a slow connection. It uses the Network Information API to determine the type of connection and if the data-saver mode is enabled. Quicklink is a lightweight library that you can use with both multiple-page apps and single-page apps to speed up navigations.
Guess.js #
Guess.js implements predictive prefetching based on a report generated by Google Analytics or a similar analytics provider. These analytics-based predictions are used to prefetch resources that the user is likely to need.
Let us now see how similar logic can be built inside the browser and what additional tooling would be required to support that.
Implementing a revamped prerendering solution #
The current prerendering implementations do not address several constraints. Following are some of the limitations that were discussed and proposed solutions that could improve prerendering.
-
Triggers: Currently
<link rel="prerender">
is the only trigger available to enable prerendering in the browser. For every link on the page which is eligible for prerendering, an additional resource hint needs to be included in the document during development.Since
prerender
requirements may change, the proposed solution should allow users to specify blanket triggers for links that match certain criteria. This has been made possible through the speculation rules API discussed in detail later. -
Cross-origin prerender: When the target link of a prerender is on the same origin, there are not many additional checks required. However, when it is pointing to a different origin, there may be privacy concerns that the browser should address. For example, user credentials should be omitted when prerendering a cross-origin page because the response should not be personalized before an actual navigation occurs. However, user-related information may be provided when the user navigates to the page. To support this two stages approach, there should be a way for the target pages to opt-in to being prerendered by a cross-origin page.
-
Prerendering browsing context: Currently, there are different types of top-level browsing contexts available. For example, a tab in a window or an iframe on a page uses a different browsing context. A similar top-level prerendering browsing context should be created for prerendered content.
The prerendering browsing context should be similar to an invisible tab and should impose additional restrictions. All disruptive APIs like playing media or permission prompts that may disrupt UI should be disabled in this browsing context.
The prerendering browsing context may also be activated. Activation should take place when the user navigates to a prerendered page. When activated, the prerendered page would switch to a new top-level browsing context.
-
Portals: Portal is a new proposed HTML element that enables seamless and instant navigations between pages. It would allow you to display the prerendered content as shown.
<portal id="myPortal" src="https://example.com/"></portal>
This element would provide a preview of the prerendered page in a prerendering browsing context. This implies that the page preview will have restricted permissions. Developers may activate the context through code on, say, a click event to expand the portal with animation to a full-page view in the embedding window.
In-browser speculation rules for prefetch
and prerender
#
One of the most important pieces of prerendering discussed in the previous section is prerendering triggers available through Speculation Rules API. The Speculation Rules API can be used by developers to indicate blanket permissions to the browser to speculate and prefetch or prerender pages that match the specified criteria.
The rules help the browser identify an initial set of pages that the website thinks would interest the user. The browser can then apply additional heuristics based on device or network characteristics, page structure, viewport, the location of the cursor, past activity on the page, and so on to decide which pages to prerender or prefetch. Thus, speculation logic like implemented by QuickLink or Guess.js may be implemented by the browser itself.
Speculation rules may be specified as a JSON object within an inline script tag
or an external resource. For example, speculation rules for prerender
may be
defined as follows:
<script type="speculationrules">
{
"prerender": [
{"source": "list",
"urls": ["/page/2"],
"score": 0.5},
{"source": "document",
"if_href_matches": ["https://*.wikipedia.org/**"],
"if_not_selector_matches": [".restricted-section *"],
"score": 0.1}
]
}
Here, two types of rules have been defined for the prerender
resource hint.
-
List rules apply to the
list
of givenurls
. Thescore
value is used to indicate how likely the user is to navigate to one of these URLs next. The score value can be between 0.0 and 1.0 with a default of 0.5. -
Document rules apply to a
document
implying that all link elements within a page are open to speculation by the browser. The subset of link elements may be chosen by including the
if_href_matches
orif_not_href_matches
andif_selector_matches
orif_not_selector_matches
filters.
Here href_matches
is used to match the link URLs, while
selector_matches
is used to match the CSS
selectors.
Same-origin prerendering trial #
An initial implementation for prerendering that covers some of the previously discussed features is available as a Chrome origin trial which will run from Chrome 94 to 98. Following are the key features included in this trial.
- Triggers: Certain features from the Speculation Rules API may be used to specify triggers to prerender same-origin URLs. Only the "list rules" format is supported at present. Also, only one prerender is allowed per page for pages with the same origin.
<script type="speculationrules">
{
"prerender": [
{"source": "list", "urls": ["https://a.test/foo"]}
]
}
</script>
If multiple rules are specified, Chrome always prerenders based on the first rule. The score property is not used. Rules may be added, but the removal of rule sets is ignored.
-
Restricted APIs: APIs that can disrupt the UI such as Geolocation, Web Serial, Notifications, Web MIDI, and Idle Detection, are deferred until the prerendered page is activated.
-
Session access: The prerendered page clones the session object of the tab-level session when it is created. Upon activation, it discards this clone and again takes the latest session object from the tab.
-
Resources: The prerendered page can load all resources like a normal page, except cross-origin iframes which are loaded only upon activation. Cookies and Storage APIs also function as they would on a normal page.
-
Trial usage: The origin trial token must be included on both the page where speculation rules are specified and the page which is the intended target of a prerender.
Using the trial #
Once you start using the trial, you can check if pages are being prerendered and study the performance impact by using existing Chrome tools.
Was the page prerendered? #
The chrome://process-internals
page can tell if a prerendered page exists.
Both the page that initiates the prerender through speculation rules and the
prerendered page will be under the same webcontents
block but can be
differentiated by the prerender
keyword.
Was the prerendered page activated? #
After prerendering, the next step is activation. To check if it was indeed the
prerendered page that was activated upon navigation and no new page load
occurred, you can open Dev Tools console after the navigation occurs. Execute
the following script and check the value of activationStart
in the console.
let activationStart = performance.getEntriesByType('navigation')[0].activationStart;
console.log(activationStart);
A non-zero value for activationStart
would imply the prerendered page was
activated.
Was it instantaneous? #
The activationStart
value is a timestamp that can be compared to the values of
First Paint and First Contentful
Paint to determine the user-centric
performance metrics for the prerendered page.
// When the activation navigation started.
let activationStart = performance.getEntriesByType('navigation')[0].activationStart;
// When First Paint occurred:
let firstPaint = performance.getEntriesByName('first-paint')[0].startTime;
// When First Contentful Paint occurred:
let firstContentfulPaint = performance.getEntriesByName('first-contentful-paint')[0].startTime;
console.log('time to first paint: ' + (firstPaint - activationStart));
console.log('time to first-contentful-paint: ' + (firstContentfulPaint - activationStart));
Comparing the values of firstPaint
and firstContentfulPaint
to those before
using the trial, can help you measure the performance impact. It is also
recommended that you use
real user monitoring (RUM)
methods to measure the performance of the origin trial.
Demo #
To check out a
simple demo for the prerendering trial,
enable the enable-prerender2
flag in Chrome.
You will need to enable this for the demo to work.
The demo provides options to prerender three different page types using <link rel=prerender>
and the Speculation Rules API. You can click on each of the
available options to check if a prerender takes place.
You can also compare the transitions for each case by clicking on the link for the page.
Feedback welcome #
The aim of this origin trial is to provide the capability of near-instantaneous page loads through the browser without relying on any external library. At the same time, it tries not to disrupt the user experience and provide a good start to a more sophisticated prerendering journey. Sign-up for the prerendering origin trial and see how well it works for your specific use cases. If you have any feedback on the trial, submit an issue to the Github repo.
There is also an ongoing trial for using
Speculation Rules for Prefetch.
Sign-up for this trial if you would like
to replace your existing prefetch
hints with browser supported speculative
prefetch.
This content originally appeared on web.dev and was authored by Addy Osmani
Addy Osmani | Sciencx (2021-09-24T00:00:00+00:00) Bringing instant page-loads to the browser through speculative prerendering. Retrieved from https://www.scien.cx/2021/09/24/bringing-instant-page-loads-to-the-browser-through-speculative-prerendering/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.