diff --git a/fetch.bs b/fetch.bs index 4d01e315b..075e8262f 100755 --- a/fetch.bs +++ b/fetch.bs @@ -114,6 +114,7 @@ urlPrefix:https://tc39.es/ecma262/#;type:dfn;spec:ecma-262
spec:dom; type:dfn; text:element +spec:dom; type:dfn; text:event; spec:infra; type:dfn; text:implementation-defined@@ -7558,6 +7559,14 @@ dictionary RequestInit { RequestDuplex duplex; RequestPriority priority; any window; // can only be set to null + FetchObserverCallback observer; +}; + +callback FetchObserverCallback = undefined (FetchObserver requestObserver, FetchObserver responseObserver); + +[Exposed=(Window,Worker)] +interface FetchObserver : EventTarget { + attribute EventHandler onprogress; }; 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: https://github.com/whatwg/dom/issues/1031#issuecomment-1233206400 --> +
Let hasUploadListeners be false. + +
Let requestObserver be null. + +
Let responseObserver be null. + +
If init["{{RequestInit/observer}}"] exists, then: + +
Let observerCallback be init["{{RequestInit/observer}}"]. + +
Set requestObserver to a {{FetchObserver}}. + +
Set responseObserver to a {{FetchObserver}}. + +
Let args be « requestObserver, responseObserver ». + +
[=invoke|Invoke=] observerCallback with args
+ and "rethrow"
. If this throws an exception, reject p with it
+ and return p.
+
+
If one or more progress
event listeners were added to
+ requestObserver, then set hasUploadListeners to true.
+
Let requestBodyTransmitted be 0. + +
Let requestBodyLength be request's body's + length, if request's body is non-null; + otherwise 0. + +
Assert: requestBodyLength is an integer. + +
Let processRequestBodyChunkLength, given a bytesLength, be these steps: + +
Increase requestBodyTransmitted by bytesLength. + +
If not roughly 50ms has passed since these steps were last invoked, then return. + +
If hasUploadListeners is true, then fire a progress event named
+ progress
at requestObserver with requestBodyTransmitted
+ and requestBodyLength.
+
Set controller to the result of calling fetch given - request and processResponse given response being - these steps: +
Let processRequestEndOfBody be these steps: + +
If hasUploadListeners is false, then return. + +
Increase requestBodyTransmitted by bytesLength. + +
Fire a progress event named progress
at requestObserver
+ with requestBodyTransmitted and requestBodyLength.
+
Let processResponse given a response be these steps:
If locallyAborted is true, then abort these steps. @@ -8615,10 +8681,17 @@ method steps are:
Resolve p with responseObject.
Set controller to the result of calling fetch given + request with processResponse set to processResponse, + processRequestBodyChunkLength set to processRequestBodyChunkLength, + and processRequestEndOfBody set to processRequestEndOfBody. +
Return p.
+TEMPORARY progress
+
To abort a fetch()
call
with a promise, request, responseObject, and an error:
@@ -9132,6 +9205,119 @@ done only by navigations). The fetch controller is also used to
process the next manual redirect for requests with
redirect mode set to "manual
".
+
+[Exposed=(Window,Worker)] +interface ProgressEvent : Event { + constructor(DOMString type, optional ProgressEventInit eventInitDict = {}); + + readonly attribute boolean lengthComputable; + readonly attribute double loaded; + readonly attribute double total; +}; + +dictionary ProgressEventInit : EventInit { + boolean lengthComputable = false; + double loaded = 0; + double total = 0; +}; ++ +
Events using the {{ProgressEvent}} interface indicate some kind of progression. + +
The
+lengthComputable
,
+loaded
, and
+total
+getter steps are to return the value they were initialized to.
+
+
+
To fire a progress event named e at +target, given transmitted and length, means to fire an event +named e at target, using {{ProgressEvent}}, with the {{ProgressEvent/loaded}} +attribute initialized to transmitted, and if length is not 0, with the +{{ProgressEvent/lengthComputable}} attribute initialized to true and the {{ProgressEvent/total}} +attribute initialized to length. + + +
This section is non-normative. + +
The suggested {{Event/type}} +attribute values for use with +events using the +{{ProgressEvent}} interface are summarized in the table below. +Specification editors are free to tune the details to their specific +scenarios, though are strongly encouraged to discuss their usage with the +WHATWG community to ensure input from people familiar with the subject. + +
{{Event/type}} attribute value + | Description + | Times + | When + |
---|---|---|---|
loadstart
+ | Progress has begun. + | Once. + | First. + |
progress
+ | In progress. + | Once or more. + | After loadstart has been
+ dispatched.
+ |
error
+ | Progression failed. + | Zero or once (mutually exclusive). + | After the last progress has
+ been
+ dispatched.
+ |
abort
+ | Progression is terminated. + | ||
timeout
+ | Progression is terminated due to preset time expiring. + | ||
load
+ | Progression is successful. + | ||
loadend
+ | Progress has stopped. + | Once. + | After one of error , abort ,
+ timeout or load has been
+ dispatched.
+ |
The error
, abort
, timeout
, and
+load
event types are mutually exclusive.
+
+
Throughout the web platform the error
, abort
,
+timeout
and load
event types have
+their {{Event/bubbles}} and {{Event/cancelable}}
+attributes initialized to false, so it is suggested that for consistency all
+events using the
+{{ProgressEvent}} interface do the same.
+
+
+
For cross-origin requests some kind of opt-in, e.g., the +CORS protocol, has to be used before events using the +{{ProgressEvent}} interface are +dispatched +as information (e.g., size) would be revealed that cannot be obtained +otherwise. +