@@ -2717,6 +2717,9 @@ functionality.
27172717<p> A <a for=fetch>fetch group</a> holds an ordered list of
27182718<dfn lt="fetch record" export for="fetch group" id=concept-fetch-record>fetch records</dfn> .
27192719
2720+ <p> A <a for=fetch>fetch group</a> holds an ordered list of
2721+ <dfn export for="fetch group" id=concept-defer=fetch-record>deferred fetch records</dfn> .
2722+
27202723<p> A <a for="fetch group">fetch record</a> has an associated
27212724<dfn export for="fetch record" id=concept-fetch-record-request>request</dfn> (a
27222725<a for=/>request</a> ).
@@ -2725,16 +2728,103 @@ functionality.
27252728<dfn export for="fetch record" id=concept-fetch-record-fetch>controller</dfn> (a
27262729<a for=/>fetch controller</a> or null).
27272730
2731+ <p> A <dfn export>deferred fetch record</dfn> is a <a for=/>struct</a> used to maintain state needed
2732+ to invoke a fetch at a later time, e.g. when a <code> Document</code> is unloaded or backgrounded. It
2733+ has the following <a for=struct>items</a> :
2734+
2735+ <dl>
2736+ <dt> <dfn export for="deferred fetch record">request</dfn>
2737+ <dd> A <a for=/>request</a>
2738+
2739+ <dt> <dfn export for="deferred fetch record">background timeout</dfn> (default null)
2740+ <dd> Null or a <a>duration</a>
2741+
2742+ <dt> <dfn export for="deferred fetch record">pending steps</dfn> (default null)
2743+ <dt> <dfn export for="deferred fetch record">invoked callback</dfn> (default null)
2744+ <dd> Null or an algortihm accepting nothing
2745+
2746+ <dt> <dfn export for="deferred fetch record">invoked</dfn> (default false)
2747+ <dd> A boolean
2748+ </dl>
2749+
2750+
27282751<hr>
27292752
2730- <p> When a <a for=fetch>fetch group</a> is
2731- <dfn export for="fetch group" id=concept-fetch-group-terminate>terminated</dfn> , for each associated
2732- <a for="fetch group">fetch record</a> whose <a for="fetch group">fetch record</a> 's
2733- <a for="fetch record">controller</a> is non-null, and whose <a for="fetch record">request</a> 's
2734- <a>done flag</a> is unset or <a for=request>keepalive</a> is false,
2735- <a for="fetch controller">terminate</a> the <a for="fetch group">fetch record</a> 's
2736- <a for="fetch record">controller</a> .
2753+ <p> When a <a for=fetch>fetch group</a> <var> fetchGroup</var> is
2754+ <dfn export for="fetch group" id=concept-fetch-group-terminate>terminated</dfn> :
2755+
2756+ <ol>
2757+ <li>
2758+ <p> <a for=list>For each</a> <a for="fetch group">deferred fetch record</a>
2759+ <var> deferredRecord</var> in <var> fetchGroup</var> 's
2760+ <a for="fetch group">deferred fetch records</a> whose <a for="deferred fetch record">invoked</a> is
2761+ false:
2762+
2763+ <ol>
2764+ <li><p> If <var> deferredRecord</var> 's <a for="deferred fetch record">pending steps</a> is not
2765+ null then <a>abort</a> <var> deferredRecord</var> 's
2766+ <a for="deferred fetch record">pending steps</a> .
2767+
2768+ <li><p> <a for=/>fetch</a> <var> deferredRecord</var> 's <a for="deferred fetch record">request</a> .
2769+ </ol>
2770+
2771+ <li><p> For each associated <a for="fetch group">fetch record</a> <var> record</var> ,
2772+ if <var> record</var> 's <a for="fetch record">controller</a> is non-null and
2773+ <var> record</var> 's <a for="fetch record">request</a>' s <a>done flag</a> is unset or
2774+ <a for=request>keepalive</a> is false, <a for="fetch controller">terminate</a> <var> record</var> 's
2775+ <a for="fetch record">controller</a> .
2776+ </ol>
2777+
2778+ <p> When a <a for=fetch>fetch group</a> <var> fetchGroup</var> is
2779+ <dfn export for="fetch group" id=concept-fetch-group-activate>activated</dfn> :
2780+ <a for=list>for each</a> <a for=/>deferred fetch record</a> <var> deferredRecord</var> in
2781+ <var> fetchGroup</var> 's <a for="fetch group">deferred fetch records</a> :
2782+
2783+ <ol>
2784+ <li>
2785+ <p> If <var> deferredRecord</var> 's <a for="deferred fetch record">invoked</a> is true then:
2786+ <ol>
2787+ <li><p> If <var> deferredRecord</var> 's <a for="deferred fetch record">invoked callback</a> is not
2788+ null then call <var> deferredRecord</var> 's <a for="deferred fetch record">invoked callback</a> .
2789+
2790+ <li><p> <a for=list>Remove</a> <var> deferredRecord</var> from <var> fetchGroup</var> 's
2791+ <a for="fetch group">deferred fetch records</a> .
2792+ </ol>
2793+
2794+ <li><p> Otherwise, if <var> deferredRecord</var> 's
2795+ <a for="deferred fetch record">pending steps</a> is not null, then <a>abort</a>
2796+ <var> deferredRecord</var> 's <a for="deferred fetch record">pending steps</a> and set
2797+ <var> deferredRecord</var> 's <a for="deferred fetch record">pending steps</a> to null.
2798+ </ol>
2799+
2800+ <p> When a <a for=fetch>fetch group</a> <var> fetchGroup</var> is
2801+ <dfn export for="fetch group" id=concept-fetch-group-deactivate>deactivated</dfn> :
27372802
2803+ <ol>
2804+ <li>
2805+ <p> <a for=list>For each</a> <a>deferred fetch record</a> <var> deferredRecord</var> in
2806+ <var> fetchGroup</var> 's <a for="fetch group">deferred fetch records</a> whose
2807+ <a for="deferred fetch record">background timeout</a> is not null: set <var> deferredRecord</var> 's
2808+ <a for="deferred fetch record">pending steps</a> to running the following steps <a>in parallel</a> :
2809+
2810+ <ol>
2811+ <li><p> Wait until <var> deferredRecord</var> 's
2812+ <a for="deferred fetch record">background timeout</a> have passed.
2813+
2814+ <li>
2815+ <p> <a>Queue a fetch task</a> to run the following steps with
2816+ <a for="fetch record">request</a> 's <a for=request>client</a>' s
2817+ <a for="environment settings object">global object</a> :
2818+
2819+ <ol>
2820+ <li><p> <a for=/>Fetch</a> <var> record</var> 's <a for="fetch record">request</a> .
2821+
2822+ <li><p> Set <var> deferredRecord</var> <a for="deferred fetch record">invoked</a> to true.
2823+ </ol>
2824+ </li>
2825+ </ol>
2826+ </li>
2827+ </ol>
27382828
27392829<h3 id=resolving-domains>Resolving domains</h3>
27402830
@@ -8562,6 +8652,117 @@ fetch("https://www.example.com/")
85628652
85638653
85648654
8655+ <h2 id=deferred-fetching>Deferred fetching</h2>
8656+
8657+ <p> Deferred fetches allow callers to request that a fetch is invoked at the latest possible moment,
8658+ when a <a>fetch group</a> is <a for="fetch group">terminated</a> , or after a timeout after it is
8659+ <a for="fetch group">deactivated</a> .
8660+
8661+ <h3 id="requesting-a-deferred-fetch">Requesting a deferred fetch</h3>
8662+
8663+ <div algorithm="request-a-deferred-fetch">
8664+ <p> To <dfn>request a deferred fetch</dfn> given a
8665+ <a for=/>request</a> <var> request</var> and a null-or-{{DOMHighResTimeStamp}}
8666+ <var> backgroundTimeout</var> (default null):
8667+
8668+ <ol>
8669+ <li><p> Assert: <var> request</var> 's <a for=request>client</a> is an
8670+ <a>environment settings object</a> .
8671+
8672+ <li> Let <var> totalScheduledDeferredBytesForOrigin</var> be 0.
8673+
8674+ <li>
8675+ <p> If <var> request</var> 's <a for=request>body</a> is not null then:
8676+
8677+ <ol>
8678+ <li><p> If <var> request</var> 's
8679+ <a for=request>body</a> 's <a for=body>length</a> is null, then throw a {{TypeError}} .
8680+
8681+ <li><p> Set <var> totalScheduledDeferredBytesForOrigin</var> to <var> request</var> 's
8682+ <a for=request>body</a> 's <a for=body>length</a> .
8683+ </ol>
8684+ </li>
8685+
8686+ <li><p> <a for=list>For each</a> <a>deferred fetch record</a> <var> deferredRecord</var> in
8687+ <var> request</var> 's <a for=request>client</a>' s <a for=fetch>fetch group</a> 's
8688+ <a for="fetch group">deferred fetch records</a> : if <var> deferredRecord</var> 's
8689+ <a for="deferred fetch record">request</a> 's <a for=request>body</a> is not null and
8690+ <var> deferredRecord</var> 's <a for="deferred fetch record">request</a>' s <a for=request>URL</a> 's
8691+ <a for=url>origin</a> is <a>same origin</a> with <var> request</var> 's <a for=request>URL</a>' s
8692+ <a for=url>origin</a> , then increment <var> totalScheduledDeferredBytesForOrigin</var> by
8693+ <var> deferredRecord</var> 's <a for="deferred fetch record">request</a>' s <a for=request>body</a> 's
8694+ <a for=body>length</a> .
8695+
8696+ <li><p> If <var> totalScheduledDeferredBytesForOrigin</var> is greater than 64 kilobytes, then
8697+ throw a {{QuotaExceededError}} .
8698+
8699+ <li><p> Let <var> deferredRecord</var> be a new <a>deferred fetch record</a> whose
8700+ <a for="deferred fetch record">request</a> is <var> request</var> .
8701+
8702+ <li><p> Set <var> deferredRecord</var> 's <a for="deferred fetch record">background timeout</a> to
8703+ <var> backgroundTimeout</var> .
8704+
8705+ <li><p> <a for=list>Append</a> <var> deferredRecord</var> to <var> request</var> 's
8706+ <a for=request>client</a> 's <a for=fetch>fetch group</a>' s
8707+ <a for="fetch group">deferred fetch records</a> .
8708+
8709+ <li><p> Return <var> deferredRecord</var> .
8710+ </ol>
8711+ </div>
8712+
8713+ <h3 id=request-deferred-fetch-method>RequestDeferredFetch method</h3>
8714+
8715+ <pre class=idl>
8716+
8717+ dictionary DeferredRequestInit : RequestInit {
8718+ DOMHighResTimeStamp? backgroundTimeout;
8719+ };
8720+
8721+ partial interface mixin WindowOrWorkerGlobalScope {
8722+ [NewObject] Promise<Response> requestDeferredFetch(RequestInfo input, optional DeferredRequestInit init = {});
8723+ };
8724+ </pre>
8725+
8726+ <div algorithm="dom-requestdeferredfetch">
8727+ <p> The
8728+ <dfn id=dom-global-requestdeferredfetch method for=WindowOrWorkerGlobalScope><code>requestDeferredFetch(<var>input</var>, <var>init</var>)</code></dfn>
8729+ method steps are:
8730+
8731+ <ol>
8732+ <li><p> Let <var> promise</var> be a new promise.
8733+
8734+ <li><p> Let <var> requestObject</var> be the result of invoking the initial value of {{Request}} as
8735+ constructor with <var> input</var> and <var> init</var> as arguments. If that threw an exception,
8736+ <a for=/>reject</a> <var> promise</var> with that exception and return <var> promise</var> .
8737+
8738+ <li><p> If <var> requestObject</var> 's <a for=Request>signal</a> is <a for=AbortSignal>aborted</a> ,
8739+ then <a for=/>reject</a> <var> promise</var> with <var> requestObject</var> 's
8740+ <a for=Request>signal</a> 's <a for=AbortSignal>abort reason</a> and return <var> promise</var> .
8741+
8742+ <li><p> Let <var> request</var> be <var> requestObject</var> 's <a for=Request>request</a> .
8743+
8744+ <li><p> Let <var> backgroundTimeout</var> be null.
8745+
8746+ <li><p> If <var> init</var> is given and <var> init</var> ["<code>backgroundTimeout</code>"]
8747+ <a for=map>exists</a> then set <var> backgroundTimeout</var> to
8748+ <var> init</var> ["<code>backgroundTimeout</code>"] .
8749+
8750+ <li><p> If <var> backgroundTimeout</var> is not a {{DOMHighResTimeStamp}} then throw a {{TypeError}} .
8751+
8752+ <li><p> Let <var> deferredRecord</var> be the result of calling
8753+ <a>request a deferred fetch</a> given <var> request</var> and <var> backgroundTimeout</var> . If that
8754+ threw an exception, <a for=/>reject</a> <var> promise</var> with that exception and return
8755+ <var> promise</var> .
8756+
8757+ <li><p> Set <var> deferredRecord</var> 's <a for="deferred fetch record">invoke callback</a> to
8758+ <a for=/>resolve</a> <var> promise</var> .
8759+
8760+ <li><p> <a for=AbortSignal lt=add>Add the following abort steps</a> to <var> requestObject</var> 's
8761+ <a for=Request>signal</a> : <a for=list>remove</a> <var> deferredRecord</var> from
8762+ <var> request</var> 's <a for=request>client</a>' s <a for=fetch>fetch group</a> 's
8763+ <a for="fetch group">deferred fetch records</a> .
8764+ </ol>
8765+
85658766<h2 id=data-urls><code>data:</code> URLs</h2>
85668767
85678768<p> For an informative description of <code> data:</code> URLs, see RFC 2397. This section replaces
0 commit comments