Skip to content

Commit c5bbcea

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

File tree

1 file changed

+189
-3
lines changed

1 file changed

+189
-3
lines changed

fetch.bs

Lines changed: 189 additions & 3 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

@@ -7558,6 +7559,14 @@ dictionary RequestInit {
75587559
RequestDuplex duplex;
75597560
RequestPriority priority;
75607561
any window; // can only be set to null
7562+
FetchObserverCallback observer;
7563+
};
7564+
7565+
callback FetchObserverCallback = undefined (FetchObserver requestObserver, FetchObserver responseObserver);
7566+
7567+
[Exposed=(Window,Worker)]
7568+
interface FetchObserver : EventTarget {
7569+
attribute EventHandler onprogress;
75617570
};
75627571

75637572
enum RequestDestination { "", "audio", "audioworklet", "document", "embed", "font", "frame", "iframe", "image", "json", "manifest", "object", "paintworklet", "report", "script", "sharedworker", "style", "track", "video", "worker", "xslt" };
@@ -8584,10 +8593,67 @@ method steps are:
85848593
https://github.com/whatwg/dom/issues/1031#issuecomment-1233206400 -->
85858594
</ol>
85868595

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

85928658
<ol>
85938659
<li><p>If <var>locallyAborted</var> is true, then abort these steps.
@@ -8615,10 +8681,17 @@ method steps are:
86158681
<li><p><a for=/>Resolve</a> <var>p</var> with <var>responseObject</var>.
86168682
</ol>
86178683

8684+
<li><p>Set <var>controller</var> to the result of calling <a for=/>fetch</a> given
8685+
<var>request</var> with <a for=fetch><i>processResponse</i></a> set to <var>processResponse</var>,
8686+
<a for=fetch><i>processRequestBodyChunkLength</i></a> set to <var>processRequestBodyChunkLength</var>,
8687+
and <a for=fetch><i>processRequestEndOfBody</i></a> set to <var>processRequestEndOfBody</var>.
8688+
86188689
<li><p>Return <var>p</var>.
86198690
</ol>
86208691
</div>
86218692

8693+
TEMPORARY <dfn id=event-fetchobserver-progress event for=FetchObserver><code>progress</code></dfn>
8694+
86228695
<div algorithm>
86238696
<p>To <dfn lt="Abort the fetch() call" export id=abort-fetch>abort a <code>fetch()</code> call</dfn>
86248697
with a <var>promise</var>, <var>request</var>, <var>responseObject</var>, and an <var>error</var>:
@@ -9132,6 +9205,119 @@ done only by navigations). The <a>fetch controller</a> is also used to
91329205
<a for="fetch controller">process the next manual redirect</a> for <a for=/>requests</a> with
91339206
<a for=request>redirect mode</a> set to "<code>manual</code>".
91349207

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

91369322
<h2 id=acknowledgments class=no-num>Acknowledgments</h2>
91379323

0 commit comments

Comments
 (0)