Skip to content

Commit 4e4130b

Browse files
committed
Add a mechanism to fetch to track progress
1 parent 0a041eb commit 4e4130b

File tree

1 file changed

+191
-4
lines changed

1 file changed

+191
-4
lines changed

fetch.bs

Lines changed: 191 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ urlPrefix:https://tc39.es/ecma262/#;type:dfn;spec:ecma-262
114114

115115
<pre class=link-defaults>
116116
spec:dom; type:dfn; text:element
117+
spec:dom; type:dfn; text:event;
117118
spec:infra; type:dfn; text:implementation-defined
118119
</pre>
119120

@@ -8512,7 +8513,18 @@ otherwise false.
85128513

85138514
<pre class=idl>
85148515
partial interface mixin WindowOrWorkerGlobalScope {
8515-
[NewObject] Promise&lt;Response> fetch(RequestInfo input, optional RequestInit init = {});
8516+
[NewObject] Promise&lt;Response> fetch(RequestInfo input, optional FetchInit init = {});
8517+
};
8518+
8519+
dictionary FetchInit : RequestInit {
8520+
FetchMonitorCallback monitor;
8521+
};
8522+
8523+
callback FetchMonitorCallback = undefined (FetchMonitor requestMonitor, FetchMonitor responseMonitor);
8524+
8525+
[Exposed=(Window,Worker)]
8526+
interface FetchMonitor : EventTarget {
8527+
attribute EventHandler onprogress;
85168528
};
85178529
</pre>
85188530

@@ -8584,10 +8596,65 @@ method steps are:
85848596
https://github.com/whatwg/dom/issues/1031#issuecomment-1233206400 -->
85858597
</ol>
85868598

8599+
<li><p>Let <var>hasUploadListeners</var> be false.
8600+
8601+
<li><p>Let <var>requestMonitor</var> be null.
8602+
8603+
<li><p>Let <var>responseMonitor</var> be null.
8604+
8605+
<li>
8606+
<p>If <var>init</var>["{{FetchInit/monitor}}"] <a for=map>exists</a>, then:
8607+
8608+
<ol>
8609+
<li><p>Let <var>monitorCallback</var> be <var>init</var>["{{FetchInit/monitor}}"].
8610+
8611+
<li><p>Set <var>requestMonitor</var> to a {{FetchMonitor}}.
8612+
8613+
<li><p>Set <var>responseMonitor</var> to a {{FetchMonitor}}.
8614+
8615+
<li><p>Let <var>args</var> be « <var>requestMonitor</var>, <var>responseMonitor</var> ».
8616+
8617+
<li><p>[=invoke|Invoke=] <var>monitorCallback</var> with <var>args</var>
8618+
and <code>"rethrow"</code>. If this throws an exception, <a for=/>reject</a> <var>p</var> with it
8619+
and return <var>p</var>.
8620+
8621+
<li><p>If one or more <a event><code>progress</code></a> event listeners were added to
8622+
<var>requestMonitor</var>, then set <var>hasUploadListeners</var> to true.
8623+
</ol>
8624+
8625+
<li><p>Let <var>requestBodyTransmitted</var> be 0.
8626+
8627+
<li><p>Let <var>requestBodyLength</var> be <var>request</var>'s <a for=request>body</a>'s
8628+
<a for=body>length</a>, if <var>request</var>'s <a for=request>body</a> is non-null;
8629+
otherwise 0.
8630+
8631+
<li><p>Assert: <var>requestBodyLength</var> is an integer.
8632+
8633+
<li>
8634+
<p>Let <var>processRequestBodyChunkLength</var>, given a <var>bytesLength</var>, be these steps:
8635+
8636+
<ol>
8637+
<li><p>Increase <var>requestBodyTransmitted</var> by <var>bytesLength</var>.
8638+
8639+
<li><p>If not roughly 50ms has passed since these steps were last invoked, then return.
8640+
8641+
<li><p>If <var>hasUploadListeners</var> is true, then <a>fire a progress event</a> named
8642+
<a event><code>progress</code></a> at <var>requestMonitor</var> with <var>requestBodyTransmitted</var>
8643+
and <var>requestBodyLength</var>.
8644+
</ol>
8645+
85878646
<li>
8588-
<p><p>Set <var>controller</var> to the result of calling <a for=/>fetch</a> given
8589-
<var>request</var> and <a for=fetch><i>processResponse</i></a> given <var>response</var> being
8590-
these steps:
8647+
<p>Let <var>processRequestEndOfBody</var> be these steps:
8648+
8649+
<ol>
8650+
<li><p>If <var>hasUploadListeners</var> is false, then return.
8651+
8652+
<li><p><a>Fire a progress event</a> named <a event><code>progress</code></a> at <var>requestMonitor</var>
8653+
with <var>requestBodyTransmitted</var> and <var>requestBodyLength</var>.
8654+
</ol>
8655+
8656+
<li>
8657+
<p>Let <var>processResponse</var> given a <var>response</var> be these steps:
85918658

85928659
<ol>
85938660
<li><p>If <var>locallyAborted</var> is true, then abort these steps.
@@ -8615,10 +8682,17 @@ method steps are:
86158682
<li><p><a for=/>Resolve</a> <var>p</var> with <var>responseObject</var>.
86168683
</ol>
86178684

8685+
<li><p>Set <var>controller</var> to the result of calling <a for=/>fetch</a> given
8686+
<var>request</var> with <a for=fetch><i>processResponse</i></a> set to <var>processResponse</var>,
8687+
<a for=fetch><i>processRequestBodyChunkLength</i></a> set to <var>processRequestBodyChunkLength</var>,
8688+
and <a for=fetch><i>processRequestEndOfBody</i></a> set to <var>processRequestEndOfBody</var>.
8689+
86188690
<li><p>Return <var>p</var>.
86198691
</ol>
86208692
</div>
86218693

8694+
TEMPORARY <dfn id=event-fetchmonitor-progress event for=FetchMonitor><code>progress</code></dfn>
8695+
86228696
<div algorithm>
86238697
<p>To <dfn lt="Abort the fetch() call" export id=abort-fetch>abort a <code>fetch()</code> call</dfn>
86248698
with a <var>promise</var>, <var>request</var>, <var>responseObject</var>, and an <var>error</var>:
@@ -9132,6 +9206,119 @@ done only by navigations). The <a>fetch controller</a> is also used to
91329206
<a for="fetch controller">process the next manual redirect</a> for <a for=/>requests</a> with
91339207
<a for=request>redirect mode</a> set to "<code>manual</code>".
91349208

9209+
<h2 id=interface-progressevent>Interface {{ProgressEvent}}</h2>
9210+
9211+
<pre class=idl>
9212+
[Exposed=(Window,Worker)]
9213+
interface ProgressEvent : Event {
9214+
constructor(DOMString type, optional ProgressEventInit eventInitDict = {});
9215+
9216+
readonly attribute boolean lengthComputable;
9217+
readonly attribute double loaded;
9218+
readonly attribute double total;
9219+
};
9220+
9221+
dictionary ProgressEventInit : EventInit {
9222+
boolean lengthComputable = false;
9223+
double loaded = 0;
9224+
double total = 0;
9225+
};
9226+
</pre>
9227+
9228+
<p><a>Events</a> using the {{ProgressEvent}} interface indicate some kind of progression.
9229+
9230+
<p>The
9231+
<dfn attribute for=ProgressEvent><code>lengthComputable</code></dfn>,
9232+
<dfn attribute for=ProgressEvent><code>loaded</code></dfn>, and
9233+
<dfn attribute for=ProgressEvent><code>total</code></dfn>
9234+
getter steps are to return the value they were initialized to.
9235+
9236+
9237+
<h3 id=firing-events-using-the-progressevent-interface>Firing events using the {{ProgressEvent}} interface</h3>
9238+
9239+
<p>To <dfn id=concept-event-fire-progress>fire a progress event</dfn> named <var>e</var> at
9240+
<var>target</var>, given <var>transmitted</var> and <var>length</var>, means to <a>fire an event</a>
9241+
named <var>e</var> at <var>target</var>, using {{ProgressEvent}}, with the {{ProgressEvent/loaded}}
9242+
attribute initialized to <var>transmitted</var>, and if <var>length</var> is not 0, with the
9243+
{{ProgressEvent/lengthComputable}} attribute initialized to true and the {{ProgressEvent/total}}
9244+
attribute initialized to <var>length</var>.
9245+
9246+
9247+
<h3 id=suggested-names-for-events-using-the-progressevent-interface>Suggested names for events using the {{ProgressEvent}} interface</h3>
9248+
9249+
<p><em>This section is non-normative.</em>
9250+
9251+
<p>The suggested {{Event/type}}
9252+
attribute values for use with
9253+
<a>events</a> using the
9254+
{{ProgressEvent}} interface are summarized in the table below.
9255+
Specification editors are free to tune the details to their specific
9256+
scenarios, though are strongly encouraged to discuss their usage with the
9257+
WHATWG community to ensure input from people familiar with the subject.
9258+
9259+
<table>
9260+
<tbody>
9261+
<tr>
9262+
<th>{{Event/type}} attribute value
9263+
<th>Description
9264+
<th>Times
9265+
<th>When
9266+
<tr>
9267+
<th><code>loadstart</code>
9268+
<td>Progress has begun.
9269+
<td>Once.
9270+
<td>First.
9271+
<tr>
9272+
<th><a event><code>progress</code></a>
9273+
<td>In progress.
9274+
<td>Once or more.
9275+
<td>After <code>loadstart</code> has been
9276+
<a>dispatched</a>.
9277+
<tr>
9278+
<th><code>error</code>
9279+
<td>Progression failed.
9280+
<td rowspan=4>Zero or once (mutually exclusive).
9281+
<td rowspan=4>After the last <a event><code>progress</code></a> has
9282+
been
9283+
<a>dispatched</a>.
9284+
<tr>
9285+
<th><code>abort</code>
9286+
<td>Progression is terminated.
9287+
<tr>
9288+
<th><code>timeout</code>
9289+
<td>Progression is terminated due to preset time expiring.
9290+
<tr>
9291+
<th><code>load</code>
9292+
<td>Progression is successful.
9293+
<tr>
9294+
<th><code>loadend</code>
9295+
<td>Progress has stopped.
9296+
<td>Once.
9297+
<td>After one of <code>error</code>, <code>abort</code>,
9298+
<code>timeout</code> or <code>load</code> has been
9299+
<a>dispatched</a>.
9300+
</table>
9301+
9302+
<p>The <code>error</code>, <code>abort</code>, <code>timeout</code>, and
9303+
<code>load</code> event types are mutually exclusive.
9304+
9305+
<p>Throughout the web platform the <code>error</code>, <code>abort</code>,
9306+
<code>timeout</code> and <code>load</code> event types have
9307+
their {{Event/bubbles}} and {{Event/cancelable}}
9308+
attributes initialized to false, so it is suggested that for consistency all
9309+
<a>events</a> using the
9310+
{{ProgressEvent}} interface do the same.
9311+
9312+
9313+
<h3 id=security-considerations>Security considerations</h3>
9314+
9315+
<p>For cross-origin requests some kind of opt-in, e.g., the
9316+
<a>CORS protocol</a>, has to be used before <a>events</a> using the
9317+
{{ProgressEvent}} interface are
9318+
<a>dispatched</a>
9319+
as information (e.g., size) would be revealed that cannot be obtained
9320+
otherwise.
9321+
91359322

91369323
<h2 id=acknowledgments class=no-num>Acknowledgments</h2>
91379324

0 commit comments

Comments
 (0)