Copyright © 2016 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and document use rules apply.
This specification defines the preload keyword that may be used with link elements. This keyword provides a declarative fetch primitive that initiates an early fetch and separates fetching from resource execution.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.
This is a work in progress and may change without any notices.
Implementers SHOULD be aware that this document is not stable. Implementers who are not taking part in the discussions are likely to find the specification changing out from under them in incompatible ways. Vendors interested in implementing this document before it eventually reaches the Candidate Recommendation stage SHOULD join the mailing lists below and take part in the discussions.
This document was published by the Web Performance Working Group as a Working Draft.
This document is intended to become a W3C Recommendation.
If you wish to make comments regarding this document, please send them to
public-web-perf@w3.org
(subscribe,
archives)
with [preload]
at the start of your email's subject.
All comments are welcome.
Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This document is governed by the 1 September 2015 W3C Process Document.
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.
img
,
script
, link
) couples resource fetching and execution. Whereas, an
application may want to fetch, but delay execution of the resource until
some condition is met.XMLHttpRequest
to avoid above behavior
incurs a serious performance penalty by hiding resource declarations from
the user agent's DOM and preload parsers. The resource fetches are only
dispatched when the relevant JavaScript is executed, which due to
abundance of blocking scripts on most pages introduces significant delays
and affects application performance.The preload keyword on link elements 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 keyword 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.
For example, the application can use the preload keyword to initiate early, high-priority, and non-render-blocking fetch of a CSS resource that can then be applied by the application at appropriate time:
<!-- preload stylesheet resource via declarative markup --> <link rel="preload" href="/styles/other.css" as="style"> <!-- or, preload stylesheet resource via JavaScript --> <script> var res = document.createElement("link"); res.rel = "preload"; res.as = "style"; res.href = "styles/other.css"; document.head.appendChild(res); </script>
Link: <https://example.com/other/styles.css>; rel=preload; as=style
As above examples illustrate, the resource can be specified via declarative markup, Link HTTP header ([RFC5988]), or scheduled via JavaScript. See use cases section for more hands-on examples of how and where preload can be used.
preload
"
The preload keyword may be used with link elements. This keyword creates an external resource link (preload link) that is used to declare a resource and its fetch properties. [HTML5]
If the preload keyword is used as an optimization to initiate earlier fetch then no additional feature detection checks are necessary: browsers that support preload will initiate earlier fetch, and those that do not will ignore it and fetch the resource as previously. Otherwise, if the application intends to rely on preload to fetch the resource, then it can execute a feature detection check to verify that it is supported.
Both prefetch
([RESOURCE-HINTS]) and preload
declare a resource and its fetch
properties, but differ in how and when the resource is fetched by the user
agent: prefetch
is an optional and low-priority fetch for a resource that
might be used by a subsequent navigation; preload
is a mandatory and
high-priority fetch for a resource that is necessary for the current
navigation. Developers should use each one accordingly to minimize resource
contention and optimize load performance.
The appropriate times to obtain the preload resource are:
Link
header that contains a preload link.
href
attribute of the link element of a preload
link that is already in a Document is changed.
crossorigin
attribute of the link element of a
preload link that is already in a Document is set, changed, or
removed.
as
attribute of the link element of a preload
link that is already in a Document is set or changed to a value
that does not or no longer matches the request destination of
the previous obtained external resource, if any.
as
attribute of the link element of a preload
link that is already in a Document but was previously not
obtained due to the as
attribute specifying an unsupported request
destination is set, removed, or changed.
type
attribute of the link element of a preload
link that is already in a Document but was previously not
obtained due to the type
attribute specifying an unsupported
request destination is set, removed, or changed.
media
attribute of the link element of a preload
link that is already in a Document contains a valid media query
list that matches the environment of the user. Otherwise, if the
media query is invalid, or evaluates to false [mediaqueries-4],
the user agent SHOULD NOT obtain the resource.
The user agent SHOULD abort the current request if the href
attribute of the link element of a preload link is changed,
removed, or its value is set to an empty string.
To obtain the preload resource, the user agent must run the following steps:
href
attribute's value is the empty string, then abort
these steps.href
attribute, relative to the element.as
attribute. If the attribute is omitted, then initialize it to the
empty string. If the provided value is not a valid request
destination, then queue a task to fire a simple event named
error
at the link element and abort these steps.[FETCH]The preload link element MUST NOT delay the load event of the element's node document.
The fetch initiated by a preload link is subject
to relevant CSP policies determined by the value of the as
attribute -
e.g. when set to image
the fetch is subject to image-src
. Similarly,
the value of the as
attribute is used to initialize request headers and
priority. If the as
attribute is omitted, the request will be
initialized with similar processing and request properties as one
initiated by XMLHttpRequest
.
Once a preload resource has been obtained, the user agent must run these steps:
load
at the link element. Otherwise, queue a task to fire
a simple event named error
at the link element.TODO: define preload "response cache". Conceptually this should probably reuse SW's cache logic? In effect, the preload cache is a UA maintained response cache with a few interesting lifetime + eviction quirks.
The user agent MUST NOT automatically execute or apply the resource against the current page context, and the user agent MUST retain the fetched response until it is matched with another request, or is no longer valid.
To match a preloaded response, the user agent must run the following steps:
TODO: define matching, see this bug and chromium discussion. This should probably live in Fetch? I.e. fetch requests should check this cache before checking browsers HTTP cache and going to network.
For example, if a JavaScript resource is fetched via a
preload link 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
link and a later fetch requesting the same resource.
partial interface HTMLLinkElement {
[CEReactions]
attribute DOMString as;
};
as
of type DOMStringRequest defaults set by the user agent via as
attribute MUST match
the default settings set by the user agent when processing a resource
with the same context. This behavior is necessary to guarantee correct
prioritization and request matching.
Example directives to preload a resource that will be consumed by...
consumer | Preload directive |
---|---|
<audio> |
<link rel=preload as=audio href=...> |
<video> |
<link rel=preload as=video href=...> |
<script> , Worker's
importScripts |
<link rel=preload as=script href=...> |
<link rel=stylesheet> , CSS @import
|
<link rel=preload as=style href=...> |
CSS @font-face | <link rel=preload as=font href=...> |
<img> , <picture> ,
srcset, imageset |
<link rel=preload as=image href=...> |
SVG's <image> , CSS *-image |
<link rel=preload as=image href=...> |
XHR, fetch | <link rel=preload href=...> |
Worker, SharedWorker | <link rel=preload as=worker href=...> |
<embed> |
<link rel=preload as=embed href=...> |
<object> |
<link rel=preload as=object href=...> |
<iframe> , <frame> |
<link rel=preload as=document
href=...> |
HTTP/2 ([RFC7540]) allows a server to pre-emptively send ("push") responses to the client. A pushed response is semantically equivalent to a server responding to a request and, similar to a preloaded response, is retained by the user agent and executed by the application when matched with another request initiated by the application. As such, from an application perspective, there is no difference between consuming a preload or a server push response.
The server MAY initiate server push for preload link resources
defined by the application for which it is authoritative. Initiating
server push eliminates the request roundtrip between client and server
for the declared preload link resource. Optionally, if the use of
server push is not desired for a resource declared via the Link
header
field ([RFC5988]), the developer MAY provide an opt-out signal to the
server via the nopush
target attribute ([RFC5988] section 5.4). For
example:
Link: </app/style.css>; rel=preload; as=style; nopush Link: </app/script.js>; rel=preload; as=script
The above example indicates to an HTTP/2 push capable
server that /app/style.css
should not be pushed (e.g. the origin may
have additional information indicating that it may already be in cache),
while /app/script.js
should be considered as a candidate for server
push.
Initiating server push for a preload link is an optional optimization. For example, the server might omit initiating push if it believes that the response is available in the client's cache: the client will process the preload directive, check the relevant caches, and initiate the request to the server if the resource is missing. Alternatively, the server might omit initiating push due to operational concerns, such as available server resources or other criteria. Finally, the use of server push is subject to negotiated HTTP/2 connection settings: the client may limit or outright disable the use of server push. Applications cannot rely on the availability and use of server push.
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words MAY, MUST, MUST NOT, SHOULD, and SHOULD NOT are to be interpreted as described in [RFC2119].
There is only one class of product that can claim conformance to this specification: a user agent.
This section is non-normative.
Preload 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, the preload 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 a preload link to declaratively specify which resources the user agent must fetch early to improve page performance:
<link rel="preload" href="/assets/font.woff2" as="font" type="font/woff2"> <link rel="preload" href="/style/other.css" as="style"> <link rel="preload" href="//example.com/resource"> <link rel="preload" href="https://fonts.example.com/font.woff2" as="font" crossorigin type="font/woff2">
Above markup initiates four resource fetches: a font resource, a
stylesheet, an unknown resource type from another origin, and a font
resource from another origin. Each fetch is initialized with appropriate
request headers and priority - the unknown type is equivalent to a fetch
initiated XMLHttpRequest
request. Further, these requests do not block
the parser or the load event.
Preload links for CORS enabled resources, such as fonts
or images with a crossorigin
attribute, must also include a
crossorigin
attribute, in order for the resource to be properly
used.
The preload link 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 link 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 link 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.
<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()">
By decoupling resource fetching from execution, the preload link provides a future-proof primitive for building performant application specific resource loading strategies.
The preload link can be specified by the developer, or be automatically generated by the application server or an optimization proxy (e.g. a CDN).
Link: <https://example.com/font.woff2>; rel=preload; as=font; type='font/woff2' Link: <https://example.com/app/script.js>; rel=preload; as=script Link: <https://example.com/logo-hires.jpg>; rel=preload; as=image Link: <https://fonts.example.com/font.woff2>; rel=preload; as=font; crossorigin; type='font/woff2'
<link rel="preload" href="//example.com/widget.html" as="iframe">
<script> var res = document.createElement("link"); res.rel = "preload"; res.as = "iframe"; res.href = "/other/widget.html"; document.head.appendChild(res); </script>
head
that contains
XMLHttpRequest
, image
, and object
requests for the
associated critical resources. However, in practice, these
implementations are brittle and often result in prioritization
conflicts with requests initiated by speculative and document
parsers, or worse, result in delayed or double downloads due to
missing request context information. The preload link
addresses these problems by providing a declarative fetch
primitive, and interoperability with the HTTP Link header, that
communicates both the URL and the context of the resource.
The link relation type below has been registered by IANA per Section 6.2.1 of [RFC5988]:
This section is non-normative.
Preload is a declarative fetch primitive that initiates early fetch of resources and separates fetching from resource execution. In effect, it is conceptually similar to initiating a scripted fetch for a resource, but with additional constraints and benefits:
as
attribute, which allows the user agent to enforce the
relevant CSP policies when initiating the preload fetch. If as
is
omitted, preload defaults to same security and privacy processing as a
call to fetch()
- i.e. subject to connect-src
.The site authors are encouraged to take the necessary precautions and
specify the relevant [CSP3], [MIXED-CONTENT], and
[REFERRER-POLICY] rules, such that the browser can enforce them when
initiating the preload request. Additionally, if preload directives are
provided via the Link
HTTP response header, then the relevant policies
should also be delivered as an HTTP response header - e.g. see
Processing Complications for CSP.
This section is non-normative.
This document reuses text from the [HTML] specification, edited by Ian Hickson, as permitted by the license of that specification.