Skip to content

Commit 797be0a

Browse files
committed
Deferred fetching
Add a JS-exposed function to request a deferred fetch. A deferred fetch would be invoked in one of two scenarios: - The document is destroyed (the fetch group is terminated) - The document is backgrounded (the fetch group is deactivated) and not restored after a certain time. A few constraints: - Deferred fetch body sizes are limited to 64KB per origin. Exceeding this would immediately reject with a QuotaExceeded. - Request body streams are not allowed. A request body, if exists, has to be a byte sequence. The JS function is called `requestDeferredFetch` but that's bikesheddable. See WICG/pending-beacon#70
1 parent 53e4c3d commit 797be0a

File tree

1 file changed

+208
-7
lines changed

1 file changed

+208
-7
lines changed

fetch.bs

Lines changed: 208 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2689,6 +2689,9 @@ functionality.
26892689
<p>A <a for=fetch>fetch group</a> holds an ordered list of
26902690
<dfn lt="fetch record" export for="fetch group" id=concept-fetch-record>fetch records</dfn>.
26912691

2692+
<p>A <a for=fetch>fetch group</a> holds an ordered list of
2693+
<dfn export for="fetch group" id=concept-defer=fetch-record>deferred fetch records</dfn>.
2694+
26922695
<p>A <a for="fetch group">fetch record</a> has an associated
26932696
<dfn export for="fetch record" id=concept-fetch-record-request>request</dfn> (a
26942697
<a for=/>request</a>).
@@ -2697,16 +2700,103 @@ functionality.
26972700
<dfn export for="fetch record" id=concept-fetch-record-fetch>controller</dfn> (a
26982701
<a for=/>fetch controller</a> or null).
26992702

2703+
<p>A <dfn export>deferred fetch record</dfn> is a <a for=/>struct</a> used to maintain state needed
2704+
to invoke a fetch at a later time, e.g. when a <code>Document</code> is unloaded or backgrounded. It
2705+
has the following <a for=struct>items</a>:
2706+
2707+
<dl>
2708+
<dt><dfn export for="deferred fetch record">request</dfn>
2709+
<dd>A <a for=/>request</a>
2710+
2711+
<dt><dfn export for="deferred fetch record">background timeout</dfn> (default null)
2712+
<dd>Null or a <a>duration</a>
2713+
2714+
<dt><dfn export for="deferred fetch record">pending steps</dfn> (default null)
2715+
<dt><dfn export for="deferred fetch record">invoked callback</dfn> (default null)
2716+
<dd>Null or an algortihm accepting nothing
2717+
2718+
<dt><dfn export for="deferred fetch record">invoked</dfn> (default false)
2719+
<dd>A boolean
2720+
</dl>
2721+
2722+
27002723
<hr>
27012724

2702-
<p>When a <a for=fetch>fetch group</a> is
2703-
<dfn export for="fetch group" id=concept-fetch-group-terminate>terminated</dfn>, for each associated
2704-
<a for="fetch group">fetch record</a> whose <a for="fetch group">fetch record</a>'s
2705-
<a for="fetch record">controller</a> is non-null, and whose <a for="fetch record">request</a>'s
2706-
<a>done flag</a> is unset or <a for=request>keepalive</a> is false,
2707-
<a for="fetch controller">terminate</a> the <a for="fetch group">fetch record</a>'s
2708-
<a for="fetch record">controller</a>.
2725+
<p>When a <a for=fetch>fetch group</a> <var>fetchGroup</var> is
2726+
<dfn export for="fetch group" id=concept-fetch-group-terminate>terminated</dfn>:
2727+
2728+
<ol>
2729+
<li>
2730+
<p><a for=list>For each</a> <a for="fetch group">deferred fetch record</a>
2731+
<var>deferredRecord</var> in <var>fetchGroup</var>'s
2732+
<a for="fetch group">deferred fetch records</a> whose <a for="deferred fetch record">invoked</a> is
2733+
false:
2734+
2735+
<ol>
2736+
<li><p>If <var>deferredRecord</var>'s <a for="deferred fetch record">pending steps</a> is not
2737+
null then <a>abort</a> <var>deferredRecord</var>'s
2738+
<a for="deferred fetch record">pending steps</a>.
2739+
2740+
<li><p><a for=/>fetch</a> <var>deferredRecord</var>'s <a for="deferred fetch record">request</a>.
2741+
</ol>
2742+
2743+
<li><p>For each associated <a for="fetch group">fetch record</a> <var>record</var>,
2744+
if <var>record</var>'s <a for="fetch record">controller</a> is non-null and
2745+
<var>record</var>'s <a for="fetch record">request</a>'s <a>done flag</a> is unset or
2746+
<a for=request>keepalive</a> is false, <a for="fetch controller">terminate</a> <var>record</var>'s
2747+
<a for="fetch record">controller</a>.
2748+
</ol>
2749+
2750+
<p>When a <a for=fetch>fetch group</a> <var>fetchGroup</var> is
2751+
<dfn export for="fetch group" id=concept-fetch-group-activate>activated</dfn>:
2752+
<a for=list>for each</a> <a for=/>deferred fetch record</a> <var>deferredRecord</var> in
2753+
<var>fetchGroup</var>'s <a for="fetch group">deferred fetch records</a>:
2754+
2755+
<ol>
2756+
<li>
2757+
<p>If <var>deferredRecord</var>'s <a for="deferred fetch record">invoked</a> is true then:
2758+
<ol>
2759+
<li><p>If <var>deferredRecord</var>'s <a for="deferred fetch record">invoked callback</a> is not
2760+
null then call <var>deferredRecord</var>'s <a for="deferred fetch record">invoked callback</a>.
2761+
2762+
<li><p><a for=list>Remove</a> <var>deferredRecord</var> from <var>fetchGroup</var>'s
2763+
<a for="fetch group">deferred fetch records</a>.
2764+
</ol>
2765+
2766+
<li><p>Otherwise, if <var>deferredRecord</var>'s
2767+
<a for="deferred fetch record">pending steps</a> is not null, then <a>abort</a>
2768+
<var>deferredRecord</var>'s <a for="deferred fetch record">pending steps</a> and set
2769+
<var>deferredRecord</var>'s <a for="deferred fetch record">pending steps</a> to null.
2770+
</ol>
2771+
2772+
<p>When a <a for=fetch>fetch group</a> <var>fetchGroup</var> is
2773+
<dfn export for="fetch group" id=concept-fetch-group-deactivate>deactivated</dfn>:
27092774

2775+
<ol>
2776+
<li>
2777+
<p><a for=list>For each</a> <a>deferred fetch record</a> <var>deferredRecord</var> in
2778+
<var>fetchGroup</var>'s <a for="fetch group">deferred fetch records</a> whose
2779+
<a for="deferred fetch record">background timeout</a> is not null: set <var>deferredRecord</var>'s
2780+
<a for="deferred fetch record">pending steps</a> to running the following steps <a>in parallel</a>:
2781+
2782+
<ol>
2783+
<li><p>Wait until <var>deferredRecord</var>'s
2784+
<a for="deferred fetch record">background timeout</a> have passed.
2785+
2786+
<li>
2787+
<p><a>Queue a fetch task</a> to run the following steps with
2788+
<a for="fetch record">request</a>'s <a for=request>client</a>'s
2789+
<a for="environment settings object">global object</a>:
2790+
2791+
<ol>
2792+
<li><p><a for=/>Fetch</a> <var>record</var>'s <a for="fetch record">request</a>.
2793+
2794+
<li><p>Set <var>deferredRecord</var> <a for="deferred fetch record">invoked</a> to true.
2795+
</ol>
2796+
</li>
2797+
</ol>
2798+
</li>
2799+
</ol>
27102800

27112801
<h3 id=resolving-domains>Resolving domains</h3>
27122802

@@ -8541,6 +8631,117 @@ fetch("https://www.example.com/")
85418631

85428632

85438633

8634+
<h2 id=deferred-fetching>Deferred fetching</h2>
8635+
8636+
<p>Deferred fetches allow callers to request that a fetch is invoked at the latest possible moment,
8637+
when a <a>fetch group</a> is <a for="fetch group">terminated</a>, or after a timeout after it is
8638+
<a for="fetch group">deactivated</a>.
8639+
8640+
<h3 id="requesting-a-deferred-fetch">Requesting a deferred fetch</h3>
8641+
8642+
<div algorithm="request-a-deferred-fetch">
8643+
<p>To <dfn>request a deferred fetch</dfn> given a
8644+
<a for=/>request</a> <var>request</var> and a null-or-{{DOMHighResTimeStamp}}
8645+
<var>backgroundTimeout</var> (default null):
8646+
8647+
<ol>
8648+
<li><p>Assert: <var>request</var>'s <a for=request>client</a> is an
8649+
<a>environment settings object</a>.
8650+
8651+
<li>Let <var>totalScheduledDeferredBytesForOrigin</var> be 0.
8652+
8653+
<li>
8654+
<p>If <var>request</var>'s <a for=request>body</a> is not null then:
8655+
8656+
<ol>
8657+
<li><p>If <var>request</var>'s
8658+
<a for=request>body</a>'s <a for=body>length</a> is null, then throw a {{TypeError}}.
8659+
8660+
<li><p>Set <var>totalScheduledDeferredBytesForOrigin</var> to <var>request</var>'s
8661+
<a for=request>body</a>'s <a for=body>length</a>.
8662+
</ol>
8663+
</li>
8664+
8665+
<li><p><a for=list>For each</a> <a>deferred fetch record</a> <var>deferredRecord</var> in
8666+
<var>request</var>'s <a for=request>client</a>'s <a for=fetch>fetch group</a>'s
8667+
<a for="fetch group">deferred fetch records</a>: if <var>deferredRecord</var>'s
8668+
<a for="deferred fetch record">request</a>'s <a for=request>body</a> is not null and
8669+
<var>deferredRecord</var>'s <a for="deferred fetch record">request</a>'s <a for=request>URL</a>'s
8670+
<a for=url>origin</a> is <a>same origin</a> with <var>request</var>'s <a for=request>URL</a>'s
8671+
<a for=url>origin</a>, then increment <var>totalScheduledDeferredBytesForOrigin</var> by
8672+
<var>deferredRecord</var>'s <a for="deferred fetch record">request</a>'s <a for=request>body</a>'s
8673+
<a for=body>length</a>.
8674+
8675+
<li><p>If <var>totalScheduledDeferredBytesForOrigin</var> is greater than 64 kilobytes, then
8676+
throw a {{QuotaExceededError}}.
8677+
8678+
<li><p>Let <var>deferredRecord</var> be a new <a>deferred fetch record</a> whose
8679+
<a for="deferred fetch record">request</a> is <var>request</var>.
8680+
8681+
<li><p>Set <var>deferredRecord</var>'s <a for="deferred fetch record">background timeout</a> to
8682+
<var>backgroundTimeout</var>.
8683+
8684+
<li><p><a for=list>Append</a> <var>deferredRecord</var> to <var>request</var>'s
8685+
<a for=request>client</a>'s <a for=fetch>fetch group</a>'s
8686+
<a for="fetch group">deferred fetch records</a>.
8687+
8688+
<li><p>Return <var>deferredRecord</var>.
8689+
</ol>
8690+
</div>
8691+
8692+
<h3 id=request-deferred-fetch-method>RequestDeferredFetch method</h3>
8693+
8694+
<pre class=idl>
8695+
8696+
dictionary DeferredRequestInit : RequestInit {
8697+
DOMHighResTimeStamp? backgroundTimeout;
8698+
};
8699+
8700+
partial interface mixin WindowOrWorkerGlobalScope {
8701+
[NewObject] Promise&lt;Response> requestDeferredFetch(RequestInfo input, optional DeferredRequestInit init = {});
8702+
};
8703+
</pre>
8704+
8705+
<div algorithm="dom-requestdeferredfetch">
8706+
<p>The
8707+
<dfn id=dom-global-requestdeferredfetch method for=WindowOrWorkerGlobalScope><code>requestDeferredFetch(<var>input</var>, <var>init</var>)</code></dfn>
8708+
method steps are:
8709+
8710+
<ol>
8711+
<li><p>Let <var>promise</var> be a new promise.
8712+
8713+
<li><p>Let <var>requestObject</var> be the result of invoking the initial value of {{Request}} as
8714+
constructor with <var>input</var> and <var>init</var> as arguments. If that threw an exception,
8715+
<a for=/>reject</a> <var>promise</var> with that exception and return <var>promise</var>.
8716+
8717+
<li><p>If <var>requestObject</var>'s <a for=Request>signal</a> is <a for=AbortSignal>aborted</a>,
8718+
then <a for=/>reject</a> <var>promise</var> with <var>requestObject</var>'s
8719+
<a for=Request>signal</a>'s <a for=AbortSignal>abort reason</a> and return <var>promise</var>.
8720+
8721+
<li><p>Let <var>request</var> be <var>requestObject</var>'s <a for=Request>request</a>.
8722+
8723+
<li><p>Let <var>backgroundTimeout</var> be null.
8724+
8725+
<li><p>If <var>init</var> is given and <var>init</var>["<code>backgroundTimeout</code>"]
8726+
<a for=map>exists</a> then set <var>backgroundTimeout</var> to
8727+
<var>init</var>["<code>backgroundTimeout</code>"].
8728+
8729+
<li><p>If <var>backgroundTimeout</var> is not a {{DOMHighResTimeStamp}} then throw a {{TypeError}}.
8730+
8731+
<li><p>Let <var>deferredRecord</var> be the result of calling
8732+
<a>request a deferred fetch</a> given <var>request</var> and <var>backgroundTimeout</var>. If that
8733+
threw an exception, <a for=/>reject</a> <var>promise</var> with that exception and return
8734+
<var>promise</var>.
8735+
8736+
<li><p>Set <var>deferredRecord</var>'s <a for="deferred fetch record">invoke callback</a> to
8737+
<a for=/>resolve</a> <var>promise</var>.
8738+
8739+
<li><p><a for=AbortSignal lt=add>Add the following abort steps</a> to <var>requestObject</var>'s
8740+
<a for=Request>signal</a>: <a for=list>remove</a> <var>deferredRecord</var> from
8741+
<var>request</var>'s <a for=request>client</a>'s <a for=fetch>fetch group</a>'s
8742+
<a for="fetch group">deferred fetch records</a>.
8743+
</ol>
8744+
85448745
<h2 id=data-urls><code>data:</code> URLs</h2>
85458746

85468747
<p>For an informative description of <code>data:</code> URLs, see RFC 2397. This section replaces

0 commit comments

Comments
 (0)