@@ -114,6 +114,7 @@ urlPrefix:https://tc39.es/ecma262/#;type:dfn;spec:ecma-262
114114
115115<pre class=link-defaults>
116116spec:dom; type:dfn; text:element
117+ spec:dom; type:dfn; text:event;
117118spec: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
75637572enum 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>
86248697with 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