This specification defines the preload relationship of the HTML Link Element (``).

Introduction

Many applications require fine-grained control over when resources are fetched, processed, and applied to the document. For example, the loading and processing of some resources may be deferred by the application to reduce resource contention and improve performance of the initial load. This behavior is typically achieved by moving resource fetching into custom resource loading logic defined by the application - i.e. resource fetches are initiated via injected elements, or via `XMLHttpRequest`, when particular application conditions are met.

However, there are also cases where some resources need to be fetched as early as possible, but their processing and execution logic is subject to application-specific requirements - e.g. dependency management, conditional loading, ordering guarantees, and so on. Currently, it is not possible to deliver this behavior without a performance penalty.

The preload relationship of the HTML Link Element provides a declarative fetch primitive that addresses the above use case of initiating an early fetch and separating fetching from resource execution. As such, preload relationship serves as a low-level primitive that enables applications to build custom resource loading and execution behaviors without hiding resources from the user agent and incurring delayed resource fetching penalties.

Preload

The preload relationship is used to declare a resource and its fetch properties. Initiating an early fetch allows the application to mask request latency and make it available sooner to the application, which can then decide when and in which order each resource is applied to the current document.

<!-- preload a widget component -->
<link rel="preload" href="/components/widget.html" as="html">

<!-- preload an application script -->
<link rel="preload" href="/app/script.js" as="javascript">

<!-- preload a CSS stylesheet -->
<link rel="preload" href="/style/style.css" as="stylesheet">

<!-- preload an image asset -->
<link rel="preload" href="//example.com/image.jpg" as="image" media="screen and (max-width: 640px)" loadpolicy="inert">
    

Fetch settings

The as attribute allows the developer to communicate the request context so that the user agent can initialize the appropriate fetch settings: relative request priority, appropriate HTTP headers, 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">
      
The resource destination context communicated via the as attribute is only used to initialize appropriate fetch settings; the communicated context is not meant to enforce security or other resource policies.

Load and processing policy

The loadpolicy attribute consists of a space-separated set of the keywords that determine the load and processing policy of the specified resource:

<link rel="preload" href="/assets/logo.jpg" as="image" loadpolicy="inert">
<link rel="preload" href="//example.com/widget">
      
inert

By default, the user agent MAY perform appropriate preprocessing on the fetched response - e.g. preparse HTML, CSS, or JavaScript responses, decode an image ahead of time, and so on. Preprocessing prepares the resource to be applied, but it MUST NOT automatically execute or apply it against the current page context. Specifying the inert policy indicates that the user agent SHOULD NOT apply any preprocessing on the response - e.g. image decodes may incur heavy resource usage that may interfere with page performance.

The decision for which preprocessing steps are performed is deferred to the user agent. The user agent MAY implement various strategies to minimize resource contention based on the type and context of fetched response, impose limits on the properties of the resource, and so on:

  • The user agent MAY allocate fewer CPU, GPU, or memory resources for preprocessing.
  • A user agent MAY abandon preprocessing due to resource constraints.
    • A user agent MAY prevent preprocessing from being initiated when there are limited resources available.
    • High resource requirements of the preloaded content may lead the user agent to cancel preprocessing - e.g. exceeded memory requirements, high CPU usage, and so on.

The above processing strategies 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.

This specification defines a single policy. Resource Hints specification defines additional policies that can be applied to preload relationship.

Process

Processing model

The user agent MUST fetch the specified resource with same default settings and priority, as indicated by the as attribute, as a resource fetch initiated by the specified context - e.g. a "script" resource specified via preload relationship should be fetched with the same priority and settings as a script fetch initiated via a `script` element.

The user agent MUST NOT delay the `load` event of the document unless the preload-initiated fetch is matched with a matching request that blocks the `load` event of the document - (see ).

Dynamic scheduling

In addition to the preload relations specified in the document markup, the application may dynamically insert and remove additional preload relations via JavaScript. The user agent MUST process dynamically inserted and removed preload relations in the same way as markup-declared relations.

  // insert new preload relation
  var res = document.createElement("link");
  res.rel = "preload";
  res.loadpolicy = "next";
  res.href = "/article/part3.html";
  document.head.appendChild(res);

  // cancel preload
  document.head.removeChild(res);
      
TODO: define what happens when element is removed from DOM?

Load and error events

Once the attempt to obtain the 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 preloadFinished(e) { ... }
  function preloadError(e)  { ... }
</script>

<!-- listen for load and error events -->
<link rel="preload" href="app.js" as="script" onload="preloadFinished()" onerror="preloadError()">
      
The application can use the `load` event on a preload relation as an indicator that the resource has been successfully fetched and is now ready to be processed by the application - e.g. a stylesheet or script can be applied to a document, and so on, without blocking on the network.

Interoperability with HTTP Link header

A user agent that support [[!RFC5988]] MUST process preload relations specified via the Link HTTP header. The application can provide one or more preload relations via multiple HTTP headers or via a comma separated list.

  Link: <https://example.com/font.woff>; rel=preload; as=font
  Link: <https://example.com/app/script.js>; rel=preload; loadpolicy=inert
  Link: <https://example.com/logo-hires.jpg>; rel=preload; as=image; media=min-resolution:2dppx
      

Matching responses with requests

Resources fetched via preload relation MUST be retained by the user agent for the duration of the current navigation until they are fetched with a matching request.

For example, if a JavaScript resource is fetched via a preload relation and the response contains a `no-cache` directive, the fetched response is retained by the user agent and is made immediately available when fetched with a matching same navigation 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 preload relation and a later fetch requesting the same resource.

The concept of "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.

Use cases

Early fetch of critical resources

Speculative parsers are used by most user agents to initiate early resource fetches while the main document parser is blocked due to a blocking script. However, these speculative parsers do not execute JavaScript, and typically only perform a shallow parse of CSS, which means that the fetch of resources specified within JavaScript and CSS is delayed until the relevant document parser is able to process the resource declaration.

In effect, most resources declarations specified within JavaScript and CSS are "hidden" from the speculative parsers and incur a performance penalty. To address this, the application can use the preload relation to declaratively specify which resources the user agent must fetch early to improve page performance.

Early fetch and application defined execution

The preload relation can be used by the application to initiate early fetch of one or more resources, as well as to provide custom logic for when and how each response should be applied to the document. The application may:

The preload relation provides a low-level and content-type agnostic primitive that enables applications to build custom resource loading and execution behaviors without incurring the penalty of delayed resource loading.

For example, preload relation enables the application to provide `async` and `defer` like semantics, which are only available on `script` elements today, but for any content-type: applying the resource immediately after it is available provides `async` functionality, whereas adding some ordering logic enables `defer` functionality. Further, this behavior can be defined across a mix of content-types - the application is in full control over when and how each resource is applied.

By decoupling resource fetching from execution, the preload relation provides a future-proof primitive for building performant application specific resource loading strategies.

Developer, server, and proxy-initiated fetching

The preload relation can be specified by the developer, or be automatically generated by the application server or an optimization proxy (e.g. a CDN).

Acknowledgments

This document reuses text from the [[!HTML]] specification, edited by Ian Hickson, as permitted by the license of that specification.