Resource Hints

Editor’s Draft, 29 September 2014

This version:
https://igrigorik.github.io/resource-hints/
Editor:
Ilya Grigorik (Google Inc.)

Abstract

Moved to: w3c.github.io/resource-hints.

Table of Contents

Issues & Feedback

1 Introduction

Modern browsers leverage a wide variety of speculative optimization techniques to anticipate user input and intent, which allows them to hide some of the networking, processing, and rendering latencies: preconnects, early fetching of resources, and prefetching and processing of resources for subsequent navigation.

The decision to initiate one or more of the above optimization is typically based on heuristic rules based on document markup and structure, navigation history, and context of the user - e.g. type of device, available compute and memory resources, network connectivity, user preferences, and so on. These techniques have proven to be successful, but can be further improved by leveraging the application and page specific knowledge of the developer or the servers responsible for generation and delivery of these resources.

For example, the application may provide the following resource hints to the user agent:

Many web applications already leverage a variety prefetching techniques, such as using XMLHttpRequest to prefetch and cache assets before they are needed. However, these implementations are app-specific, are not interoperable with the browser-provided primitives, and do not provide the same level of performance, or worse, conflict and result in delayed or unnecessary downloads that degrade overall page performance.

This specification defines preconnect, preload, and prerender hints that the developer, or the server generating or delivering the resources, can use in an interoperable way to assist the user agent in the decision process of which origins it should connect to, which resources it should fetch to improve performance, and which resources may be required by the next navigation.

2 Resource Hints

Resource hints are used to assist the user agent in the decision making process of which optimizations can be applied when the page is being loaded, or as the user is interacting with the application.

2.1 Preconnect

The preconnect hint is used to indicate an origin that will be used to fetch required resources. Initiating an early connection, which includes the DNS lookup, TCP handshake, and optional TLS negotiation, allows the user agent to mask the high costs of connection establishment latency.

<link rel="preconnect" href="//example.com">
<link rel="preconnect" href="//cdn.example.com">

The optimal number of connections per origin is dependent on the negotiated protocol, users current connectivity profile, available device resources, and other context specific variables. As a result, this decision is deferred to the user agent, which is in the best position to determine the optimal number.

The user agent should perform the full connection handshake (DNS+TCP for HTTP, and DNS+TCP+TLS for HTTPS origins) whenever possible, but is allowed to elect to perform a partial handshake (DNS only for HTTP, and DNS or DNS+TCP for HTTPS origins), or skip it entirely, due to resource constraints or other reasons.

The full resource URL may not be known until the page is being constructed by the user agent - e.g. conditional loading logic, UA adaptation, etc. However, the origin from which one or more of these resources will be fetched is often known ahead of time by the developer or the server generating the response. In such cases, a preconnect hint can be used to initiate an early connection handshake such that when the resource URL is determined, the user agent can dispatch the request without first blocking on connection negotiation.
Many sites rely on redirects for analytics and to anonymize the referrer before sending the user to the final destination. Because the destination is known ahead of time, a preconnect hint can be used to initiate the connection handshake with the destination origin in parallel with the processing of the redirect.

Note that this behavior requires ability to dynamically inject a preconnect hint (e.g. as part of a JavaScript handler), and for the preconnect processing to proceed across page navigations.

2.2 Preload

The preload hint is used to indicate the URL of a resource that should be fetched as early as possible by the user agent. Initiating an early fetch allows the user agent to mask the request latency of the resource and make it available sooner to the application.

<link rel="preload" href="/assets/font.woff" as="font">
<link rel="preload" href="/assets/logo.webp" as="image">
<link rel="preload" href="//example.com/app.js" as="script">
<link rel="preload" href="//example.com/mobile-ui-framework.js" as="script" media="screen and (max-width: 640px)">
Note: resource hints are subject to media query processing rules: the user agent must initiate resource fetch when media attribute’s value matches the environment, and must not initiate the fetch otherwise.
The preload hint can be used by the application to initiate early fetch, but delay processing of the received response - e.g. fetch a CSS stylesheet and apply it at some later time, fetch a JavaScript asset and execute it later, and so on. The preload fetches do not block the document load event and allow the application to determine which resources are applied, when they are executed, and in which order.
Speculative parsers do not execute JavaScript and perform a shallow parse of CSS, which means that the fetch of resources specified within JavaScript and CSS is delayed until the document parser is able to process the resource declaration. By using a preload hint the application can declaratively specify which resources the user agent should fetch early to mask the request latency and improve page performance.
The preload hint can be generated both by the application and an optimization proxy (e.g. a CDN) to accelerate fetch and delivery of required resources.
  1. The application can specify preload hints, allowing:
    • The optimization proxy to initiate early fetch of the associated resources and place them into its cache, thus reducing or eliminating the latency of retrieving resources from the origin.
    • The user agent to initiate early fetch of required resources - see example above.
  2. The optimization proxy can specify preload hints on behalf of the application:
    • The proxy can observe and infer required resources based on past request patterns, allowing it to automate generation of relevant preload hints to improve performance.
    • The proxy can deliver inferred preload hints to the user agent while it is blocked on the response from the origin, allowing the user agent to begin fetching required resources.
    Many optimization proxies already implement the "early flush" strategy where references to required resources are delivered to the user agent while the proxy is blocked on the response from the origin. Today, this is typically done by synthesizing a document <head> that contains XHR, image, and object requests. However, in practice, these implementations often result in prioritization conflicts with requests initiated by speculative and document parsers, or worse, result in delayed or double downloads due to missing context information.

    The preload hint addresses these problems by providing a declarative hint that communicates both the URL and the context of the resource.

2.3 Prerender

The prerender hint is used to indicate the URL and the context of a resource required by the next navigation. Initiating an early fetch of the specified resource allows the user agent to mask the request latency, and optional preprocessing of the fetched response allows the user agent to deliver an experience of instant delivery and execution once the resource is requested.

<link rel="prerender" href="//example.com/thankyou.html">
<link rel="prerender" href="//example.com/application.js" as="script">
<link rel="prerender" href="//example.com/image.webp" as="image" media="max-width: 640px">

Note: prerender is not restricted to HTML and may be used to load and preprocess any content-type.

The user agent may perform appropriate preprocessing depending on the type and destination context of the response - e.g. decode an image, parse the HTML markup, parse the HTML markup and initiate fetches for critical subresources, and so on. The decision for which preprocessing steps are performed is deferred to the user agent and is a function of runtime context and specified hint probability - see §3.2 Required vs. speculative hints.

Prerendering should not negatively impact the performance of the current navigation context. Due to the need to fetch and optionally preprocess the specified resource and its associated assets, prerendering may result in high contention for CPU, GPU, memory, and network resources. As a result, the user agent may implement various strategies to minimize resource contention based on type and context of fetched response, impose limits on the properties of the resource that is being prerendered, and so on:

Note: The above examples are not an exhaustive list. The decision which strategies to implement for each content-type and how to enforce them is deferred to the user agent. For a hands-on example of HTML prerendering strategies, see Chromium prerendering wiki page.

The user agent should not cancel outstanding prerender requests when a new navigation is triggered as they may be required by the next page. However, the user agent may cancel these requests once it determines that they are not required by the new destination.

To ensure compatibility and improve the success rate of prerender requests the target page should use the [PAGE-VISIBILITY] to determine the visibility state of the page as it is being rendered and implement appropriate logic to avoid actions that may cause the prerender to be abandoned (e.g. non-idempotent requests), or unwanted side-effects from being triggered (e.g. analytics beacons firing prior to the page being displayed).

The prerender hint can be used to implement a prefetch strategy that leverages app-specific knowledge about the next navigation based on content, structure, analytics, or other signals - e.g. high-likelihood search results, paginated content or step-driven flows, aggregated analytics or per-user behavior, and so on.

For example, an image gallery may have knowledge about the likelihood of the next photo or page that may be requested by the user. To provide an improved experience the application can ask the user agent to begin fetching required resources (individual photos, critical resources, or the full page) before the next navigation is triggered.

Alternatively, instead of anticipating user activity, the application can react to user input and dynamically schedule prerender requests based on its knowledge of resources that will be required by the next navigation target - i.e. the application may capture a click event and provide prerender hints to the user agent before the current page is unloaded.

3 Processing model

3.1 Fetch settings

Specifying the as attribute allows the developer to communicate the resource destination context, such that the user agent can initialize the appropriate fetch settings: HTTP headers, request priority, and so on.

<link rel="preload" href="/assets/font.woff" as="font">
<link rel="preload" href="/assets/logo.webp" as="image">
<link rel="preload" href="//example.com/widget">

In addition to the fetch settings set by the resource destination context, the user agent must account for the relative hint priority: preload requests must have higher priority than prerender requests with the same context. In the case where the same resource has mixed prioritization hints, the user agent should resolve the conflict:

Note: the resource destination context communicated via the as attribute is used to initialize appropriate fetch settings; the communicated context should not be used to enforce security or other resource policies.

3.2 Required vs. speculative hints

In addition to specifying the hint type, its fetch parameters, and the resource URL, the developer can communicate the expected probability that the resource will be used in the current or next navigation context.

<link rel="preconnect" href="//sub.example.com" probability="0.22">
<link rel="preload" href="//example.com/application.js" probability="0.75">
<link rel="prerender" href="//example.com/thankyou.html" probability="1.0">

The probability attribute is a float value in the [0.0-1.0] range:

Speculative hints are processed on a best effort basis by the user agent based on the runtime context of the user agent — availability of CPU, GPU, memory, and networking resources — developer specified probability indicating the likelihood of that resource being used, and specified user preferences.

To optimize the overall user experience the user agent should account for local context and specified probability of a speculative hint. For example, on a resource constrained device the user agent may decide to only execute high probability hints. Alternatively, it may decide to perform partial processing of the hint, such as downgrading preload to preconnect, prerender to preload, performing a partial prerender, and so on.

Performing a partial optimization allows the user agent to improve performance even if a full optimization cannot be performed. Conversely, on a device with sufficient resources, the user agent may execute all of the specified hints as far as possible.

TBD: do we need a carve-out clause for "required prerender hint"? E.g. current browsers allow the user to opt-out from prerender. However, required preconnect and preload hints, which apply to current context, must be respected by the user agent.

3.3 Hint execution

The user agent must not delay the load event of the document unless the hint-initiated fetch is matched with a matching request that blocks the load event of the document.

Once the the attempt to obtain the hint-initiated resource is complete, the user agent must, if the fetch was successful, queue a task to fire a simple event named load at the link element, or, if the fetch failed to complete for any reason, queue a task to fire a simple event named error at the link element.

<script>
  function hintLoaded() { ... }
  function hintError()  { ... }

  var hint = document.createElement("link")
  hint.setAttribute("rel", "preload")
  hint.setAttribute("as", "image")
  hint.setAttribute("href", "/image.jpeg")
  document.getElementsByTagName("head")[0].appendChild(hint)

  // listen for load/error events
  hint.addEventListener("load", function() { hintLoaded() })
  hint.addEventListener("error", function() { hintError() })
</script>

<!-- listen for load/error events -->
<link rel="preload" href="app.js" as="script" onload="hintLoaded()" onerror="hintError()">
Note: the decision on whether a speculative hint is executed, and if so, whether full or partial processing is applied is deferred to the user agent. As a result, the load and error events are not guaranteed to fire for a speculative hint, and when they do, do not guarantee that full processing was applied.
The application may use the load event on a preload hint as an indicator that the resource has been successfully fetched and is now ready to be processed by the application - e.g. the image is ready to be decoded, a stylesheet or script may be applied, and so on, without blocking on the network.

3.4 Dynamic scheduling

In addition to the hints specified in the document markup, the application may have runtime resource hints based on user context or other signals. The user agent should process dynamically inserted resource hints in addition to and in the same way as document specified hints.

// insert new prerender hint
var hint = document.createElement("link")
hint.setAttribute("rel", "prerender")
hint.setAttribute("href", "/article/part3.html")
document.getElementsByTagName("head")[0].appendChild(hint)
// cancel prerender
document.getElementsByTagName("head")[0].removeChild(hint);

The removal of the hint from the document should cancel the optimization if it is being processed and prevent it from executing if it has not yet been invoked.

The application may use dynamic scheduling to react and adapt to user initiated actions - e.g. initiate a speculative resource fetch in response to recent user activity, cancel previous speculative fetch, and so on.

The user agent should process resource hints specified via the Link HTTP header.

Link: <https://example.com>; rel=preconnect
Link: <https://example.com/font.woff>; rel=preload; as=font
Link: <https://example.com/article/part2.html>; rel=prerender
Link: <https://example.com/logo-hires.jpg>; rel=prerender; as=image; media=min-resolution:2dppx

The application may provide one or more of the same type of hint via multiple HTTP headers or via a comma separated list. The user agent should process such hints in addition to and in the same way as document specified and dynamically scheduled resource hints.

Delivering resource hints via Link header allows automated optimization services running on origin or upstream servers (e.g. CDN) to leverage and emit resource hints without modifying the delivered response.

3.6 Matching hint responses with requests

Resources fetched via preload and prerender are retained by the user agent until they are fetched with a matching request. The user agent may decide to discard the retained response due to resource constraints, a timeout (recommended, at least 300 seconds), or other reasons.

A JavaScript resource is fetched via preload and the response contains a no-cache directive. The fetched response is retained by the user agent and is immediately returned when fetched with a matching request at a later time - e.g. via a script tag or other means. This ensures that the user agent does not incur an unnecessary revalidation, or a duplicate download, between the initial resource fetch initiated via the specified resource hint and a later fetch requesting the same resource.

Note: "matching" is not currently defined or interoperable across user agents. This should be fixed, but it is out of scope of this specification. For further discussion see this bug and chromium discussion.

Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

References

Normative References

[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. URL: http://www.ietf.org/rfc/rfc2119.txt

Informative References

[FETCH]
Anne van Kesteren. Fetch. Living Standard. URL: http://fetch.spec.whatwg.org/
[PAGE-VISIBILITY]
Jatinder Mann; Arvind Jain. Page Visibility. 14 May 2013. W3C Recommendation. URL: http://www.w3.org/TR/2013/REC-page-visibility-20130514/

Index

Property index

No properties defined.

Issues Index

TBD: do we need a carve-out clause for "required prerender hint"? E.g. current browsers allow the user to opt-out from prerender. However, required preconnect and preload hints, which apply to current context, must be respected by the user agent.