@@ -5501,13 +5501,15 @@ dictionary Transformer {
55015501 TransformerStartCallback start;
55025502 TransformerTransformCallback transform;
55035503 TransformerFlushCallback flush;
5504+ TransformerCancelCallback cancel;
55045505 any readableType;
55055506 any writableType;
55065507};
55075508
55085509callback TransformerStartCallback = any (TransformStreamDefaultController controller);
55095510callback TransformerFlushCallback = Promise<undefined> (TransformStreamDefaultController controller);
55105511callback TransformerTransformCallback = Promise<undefined> (any chunk, TransformStreamDefaultController controller);
5512+ callback TransformerCancelCallback = Promise<undefined> (any reason);
55115513</xmp>
55125514
55135515<dl>
@@ -5570,6 +5572,25 @@ callback TransformerTransformCallback = Promise<undefined> (any chunk, Transform
55705572 {{Transformer/flush|flush()}} ; the stream is already in the process of successfully closing down,
55715573 and terminating it would be counterproductive.)
55725574
5575+ <dt> <dfn dict-member for="Transformer" lt="cancel">cancel(<var ignore>reason</var>)</dfn> </dt>
5576+ <dd>
5577+ <p> A function called when the [=readable side=] is cancelled, or when the [=writable side=] is
5578+ aborted.
5579+
5580+ <p> Typically this is used to clean up underlying transformer resources when the stream is aborted
5581+ or cancelled.
5582+
5583+ <p> If the cancellation process is asynchronous, the function can return a promise to signal
5584+ success or failure; the result will be communicated to the caller of
5585+ {{WritableStream/abort()|stream.writable.abort()}} or
5586+ {{ReadableStream/cancel()|stream.readable.cancel()}} . Throwing an exception is treated the same
5587+ as returning a rejected promise.
5588+
5589+ <p> (Note that there is no need to call
5590+ {{TransformStreamDefaultController/terminate()|controller.terminate()}} inside
5591+ {{Transformer/cancel|cancel()}} ; the stream is already in the process of cancelling/aborting, and
5592+ terminating it would be counterproductive.)
5593+
55735594 <dt> <dfn dict-member for="Transformer">readableType</dfn> </dt>
55745595 <dd>
55755596 <p> This property is reserved for future use, so any attempts to supply a value will throw an
@@ -5583,8 +5604,8 @@ callback TransformerTransformCallback = Promise<undefined> (any chunk, Transform
55835604
55845605The <code> controller</code> object passed to {{Transformer/start|start()}} ,
55855606{{Transformer/transform|transform()}} , and {{Transformer/flush|flush()}} is an instance of
5586- {{TransformStreamDefaultController}} , and has the ability to enqueue [=chunks=] to the [=readable
5587- side=] , or to terminate or error the stream.
5607+ {{TransformStreamDefaultController}} , and has the ability to enqueue [=chunks=] to the
5608+ [=readable side=] , or to terminate or error the stream.
55885609
55895610<h4 id="ts-prototype">Constructor and properties</h4>
55905611
@@ -5738,6 +5759,16 @@ the following table:
57385759 <th> Internal Slot</th>
57395760 <th> Description (<em> non-normative</em> )</th>
57405761 <tbody>
5762+ <tr>
5763+ <td> <dfn>\[[cancelAlgorithm]]</dfn>
5764+ <td class="non-normative"> A promise-returning algorithm, taking one argument (the reason for
5765+ cancellation), which communicates a requested cancellation to the [=transformer=]
5766+ <tr>
5767+ <td> <dfn>\[[finishPromise]]</dfn>
5768+ <td class="non-normative"> A promise which resolves on completion of either the
5769+ [=TransformStreamDefaultController/[[cancelAlgorithm]]=] or the
5770+ [=TransformStreamDefaultController/[[flushAlgorithm]]=] . If this field is unpopulated (that is,
5771+ undefined), then neither of those algorithms have been [=invoked=] yet
57415772 <tr>
57425773 <td> <dfn>\[[flushAlgorithm]]</dfn>
57435774 <td class="non-normative"> A promise-returning algorithm which communicates a requested close to
@@ -5831,8 +5862,7 @@ The following abstract operations operate on {{TransformStream}} instances at a
58315862 1. Let |pullAlgorithm| be the following steps:
58325863 1. Return ! [$TransformStreamDefaultSourcePullAlgorithm$] (|stream|).
58335864 1. Let |cancelAlgorithm| be the following steps, taking a |reason| argument:
5834- 1. Perform ! [$TransformStreamErrorWritableAndUnblockWrite$] (|stream|, |reason|).
5835- 1. Return [=a promise resolved with=] undefined.
5865+ 1. Return ! [$TransformStreamDefaultSourceCancelAlgorithm$] (|stream|, |reason|).
58365866 1. Set |stream|.[=TransformStream/[[readable]]=] to ! [$CreateReadableStream$] (|startAlgorithm|,
58375867 |pullAlgorithm|, |cancelAlgorithm|, |readableHighWaterMark|, |readableSizeAlgorithm|).
58385868 1. Set |stream|.[=TransformStream/[[backpressure]]=] and
@@ -5866,12 +5896,7 @@ The following abstract operations operate on {{TransformStream}} instances at a
58665896 1. Perform ! [$TransformStreamDefaultControllerClearAlgorithms$] (|stream|.[=TransformStream/[[controller]]=] ).
58675897 1. Perform !
58685898 [$WritableStreamDefaultControllerErrorIfNeeded$] (|stream|.[=TransformStream/[[writable]]=] .[=WritableStream/[[controller]]=] , |e|).
5869- 1. If |stream|.[=TransformStream/[[backpressure]]=] is true, perform ! [$TransformStreamSetBackpressure$] (|stream|,
5870- false).
5871-
5872- <p class="note"> The [$TransformStreamDefaultSinkWriteAlgorithm$] abstract operation could be
5873- waiting for the promise stored in the [=TransformStream/[[backpressureChangePromise]]=] slot to
5874- resolve. The call to [$TransformStreamSetBackpressure$] ensures that the promise always resolves.
5899+ 1. Perform ! [$TransformStreamUnblockWrite$] (|stream|).
58755900</div>
58765901
58775902<div algorithm>
@@ -5886,6 +5911,19 @@ The following abstract operations operate on {{TransformStream}} instances at a
58865911 1. Set |stream|.[=TransformStream/[[backpressure]]=] to |backpressure|.
58875912</div>
58885913
5914+ <div algorithm>
5915+ <dfn abstract-op lt="TransformStreamUnblockWrite"
5916+ id="transform-stream-unblock-write"> TransformStreamUnblockWrite(|stream|)</dfn> performs the
5917+ following steps:
5918+
5919+ 1. If |stream|.[=TransformStream/[[backpressure]]=] is true, perform ! [$TransformStreamSetBackpressure$] (|stream|,
5920+ false).
5921+
5922+ <p class="note"> The [$TransformStreamDefaultSinkWriteAlgorithm$] abstract operation could be
5923+ waiting for the promise stored in the [=TransformStream/[[backpressureChangePromise]]=] slot to
5924+ resolve. The call to [$TransformStreamSetBackpressure$] ensures that the promise always resolves.
5925+ </div>
5926+
58895927<h4 id="ts-default-controller-abstract-ops">Default controllers</h4>
58905928
58915929The following abstract operations support the implementaiton of the
@@ -5894,7 +5932,8 @@ The following abstract operations support the implementaiton of the
58945932<div algorithm>
58955933 <dfn abstract-op lt="SetUpTransformStreamDefaultController"
58965934 id="set-up-transform-stream-default-controller"> SetUpTransformStreamDefaultController(|stream|,
5897- |controller|, |transformAlgorithm|, |flushAlgorithm|)</dfn> performs the following steps:
5935+ |controller|, |transformAlgorithm|, |flushAlgorithm|, |cancelAlgorithm|)</dfn> performs the
5936+ following steps:
58985937
58995938 1. Assert: |stream| [=implements=] {{TransformStream}} .
59005939 1. Assert: |stream|.[=TransformStream/[[controller]]=] is undefined.
@@ -5903,6 +5942,7 @@ The following abstract operations support the implementaiton of the
59035942 1. Set |controller|.[=TransformStreamDefaultController/[[transformAlgorithm]]=] to
59045943 |transformAlgorithm|.
59055944 1. Set |controller|.[=TransformStreamDefaultController/[[flushAlgorithm]]=] to |flushAlgorithm|.
5945+ 1. Set |controller|.[=TransformStreamDefaultController/[[cancelAlgorithm]]=] to |cancelAlgorithm|.
59065946</div>
59075947
59085948<div algorithm>
@@ -5916,15 +5956,20 @@ The following abstract operations support the implementaiton of the
59165956 1. If |result| is an abrupt completion, return [=a promise rejected with=] |result|.\[[Value]] .
59175957 1. Otherwise, return [=a promise resolved with=] undefined.
59185958 1. Let |flushAlgorithm| be an algorithm which returns [=a promise resolved with=] undefined.
5959+ 1. Let |cancelAlgorithm| be an algorithm which returns [=a promise resolved with=] undefined.
59195960 1. If |transformerDict|["{{Transformer/transform}}"] [=map/exists=] , set |transformAlgorithm| to an
59205961 algorithm which takes an argument |chunk| and returns the result of [=invoking=]
59215962 |transformerDict|["{{Transformer/transform}}"] with argument list « |chunk|,
59225963 |controller| » and [=callback this value=] |transformer|.
59235964 1. If |transformerDict|["{{Transformer/flush}}"] [=map/exists=] , set |flushAlgorithm| to an
59245965 algorithm which returns the result of [=invoking=] |transformerDict|["{{Transformer/flush}}"]
59255966 with argument list « |controller| » and [=callback this value=] |transformer|.
5967+ 1. If |transformerDict|["{{Transformer/cancel}}"] [=map/exists=] , set |cancelAlgorithm| to an
5968+ algorithm which takes an argument |reason| and returns the result of [=invoking=]
5969+ |transformerDict|["{{Transformer/cancel}}"] with argument list « |reason| » and
5970+ [=callback this value=] |transformer|.
59265971 1. Perform ! [$SetUpTransformStreamDefaultController$] (|stream|, |controller|,
5927- |transformAlgorithm|, |flushAlgorithm|).
5972+ |transformAlgorithm|, |flushAlgorithm|, |cancelAlgorithm| ).
59285973</div>
59295974
59305975<div algorithm>
@@ -5943,6 +5988,7 @@ The following abstract operations support the implementaiton of the
59435988
59445989 1. Set |controller|.[=TransformStreamDefaultController/[[transformAlgorithm]]=] to undefined.
59455990 1. Set |controller|.[=TransformStreamDefaultController/[[flushAlgorithm]]=] to undefined.
5991+ 1. Set |controller|.[=TransformStreamDefaultController/[[cancelAlgorithm]]=] to undefined.
59465992</div>
59475993
59485994<div algorithm>
@@ -6033,36 +6079,89 @@ side=] of [=transform streams=].
60336079 id="transform-stream-default-sink-abort-algorithm"> TransformStreamDefaultSinkAbortAlgorithm(|stream|,
60346080 |reason|)</dfn> performs the following steps:
60356081
6036- 1. Perform ! [$TransformStreamError$] (|stream|, |reason|).
6037- 1. Return [=a promise resolved with=] undefined.
6082+ 1. Let |controller| be |stream|.[=TransformStream/[[controller]]=] .
6083+ 1. If |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] is not undefined, return
6084+ |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] .
6085+ 1. Let |readable| be |stream|.[=TransformStream/[[readable]]=] .
6086+ 1. Let |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] be a new promise.
6087+ 1. Let |cancelPromise| be the result of performing
6088+ |controller|.[=TransformStreamDefaultController/[[cancelAlgorithm]]=] , passing |reason|.
6089+ 1. Perform ! [$TransformStreamDefaultControllerClearAlgorithms$] (|controller|).
6090+ 1. [=React=] to |cancelPromise|:
6091+ 1. If |cancelPromise| was fulfilled, then:
6092+ 1. If |readable|.[=ReadableStream/[[state]]=] is "`errored`", [=reject=]
6093+ |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] with
6094+ |readable|.[=ReadableStream/[[storedError]]=] .
6095+ 1. Otherwise:
6096+ 1. Perform ! [$ReadableStreamDefaultControllerError$] (|readable|.[=ReadableStream/[[controller]]=] , |reason|).
6097+ 1. [=Resolve=] |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] with undefined.
6098+ 1. If |cancelPromise| was rejected with reason |r|, then:
6099+ 1. Perform ! [$ReadableStreamDefaultControllerError$] (|readable|.[=ReadableStream/[[controller]]=] , |r|).
6100+ 1. [=Reject=] |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] with |r|.
6101+ 1. Return |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] .
60386102</div>
60396103
60406104<div algorithm>
60416105 <dfn abstract-op lt="TransformStreamDefaultSinkCloseAlgorithm"
60426106 id="transform-stream-default-sink-close-algorithm"> TransformStreamDefaultSinkCloseAlgorithm(|stream|)</dfn>
60436107 performs the following steps:
60446108
6045- 1. Let |readable| be |stream|.[=TransformStream/[[readable]]=] .
60466109 1. Let |controller| be |stream|.[=TransformStream/[[controller]]=] .
6110+ 1. If |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] is not undefined, return
6111+ |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] .
6112+ 1. Let |readable| be |stream|.[=TransformStream/[[readable]]=] .
6113+ 1. Let |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] be a new promise.
60476114 1. Let |flushPromise| be the result of performing
60486115 |controller|.[=TransformStreamDefaultController/[[flushAlgorithm]]=] .
60496116 1. Perform ! [$TransformStreamDefaultControllerClearAlgorithms$] (|controller|).
6050- 1. Return the result of [=reacting =] to |flushPromise|:
6117+ 1. [=React =] to |flushPromise|:
60516118 1. If |flushPromise| was fulfilled, then:
6052- 1. If |readable|.[=ReadableStream/[[state]]=] is "`errored`", throw
6119+ 1. If |readable|.[=ReadableStream/[[state]]=] is "`errored`", [=reject=]
6120+ |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] with
60536121 |readable|.[=ReadableStream/[[storedError]]=] .
6054- 1. Perform !
6055- [$ReadableStreamDefaultControllerClose$] (|readable|.[=ReadableStream/[[controller]]=] ).
6122+ 1. Otherwise:
6123+ 1. Perform ! [$ReadableStreamDefaultControllerClose$] (|readable|.[=ReadableStream/[[controller]]=] ).
6124+ 1. [=Resolve=] |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] with undefined.
60566125 1. If |flushPromise| was rejected with reason |r|, then:
6057- 1. Perform ! [$TransformStreamError$] (|stream|, |r|).
6058- 1. Throw |readable|.[=ReadableStream/[[storedError]]=] .
6126+ 1. Perform ! [$ReadableStreamDefaultControllerError$] (|readable|.[=ReadableStream/[[controller]]=] , |r|).
6127+ 1. [=Reject=] |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] with |r|.
6128+ 1. Return |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] .
60596129</div>
60606130
60616131<h4 id="ts-default-source-abstract-ops">Default sources</h4>
60626132
60636133The following abstract operation is used to implement the [=underlying source=] for the [=readable
60646134side=] of [=transform streams=] .
60656135
6136+ <div algorithm>
6137+ <dfn abstract-op lt="TransformStreamDefaultSourceCancelAlgorithm"
6138+ id="transform-stream-default-source-cancel"> TransformStreamDefaultSourceCancelAlgorithm(|stream|,
6139+ |reason|)</dfn> performs the following steps:
6140+
6141+ 1. Let |controller| be |stream|.[=TransformStream/[[controller]]=] .
6142+ 1. If |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] is not undefined, return
6143+ |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] .
6144+ 1. Let |writable| be |stream|.[=TransformStream/[[writable]]=] .
6145+ 1. Let |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] be a new promise.
6146+ 1. Let |cancelPromise| be the result of performing
6147+ |controller|.[=TransformStreamDefaultController/[[cancelAlgorithm]]=] , passing |reason|.
6148+ 1. Perform ! [$TransformStreamDefaultControllerClearAlgorithms$] (|controller|).
6149+ 1. [=React=] to |cancelPromise|:
6150+ 1. If |cancelPromise| was fulfilled, then:
6151+ 1. If |writable|.[=WritableStream/[[state]]=] is "`errored`", [=reject=]
6152+ |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] with
6153+ |writable|.[=WritableStream/[[storedError]]=] .
6154+ 1. Otherwise:
6155+ 1. Perform ! [$WritableStreamDefaultControllerErrorIfNeeded$] (|writable|.[=WritableStream/[[controller]]=] , |reason|).
6156+ 1. Perform ! [$TransformStreamUnblockWrite$] (|stream|).
6157+ 1. [=Resolve=] |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] with undefined.
6158+ 1. If |cancelPromise| was rejected with reason |r|, then:
6159+ 1. Perform ! [$WritableStreamDefaultControllerErrorIfNeeded$] (|writable|.[=WritableStream/[[controller]]=] , |r|).
6160+ 1. Perform ! [$TransformStreamUnblockWrite$] (|stream|).
6161+ 1. [=Reject=] |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] with |r|.
6162+ 1. Return |controller|.[=TransformStreamDefaultController/[[finishPromise]]=] .
6163+ </div>
6164+
60666165<div algorithm>
60676166 <dfn abstract-op lt="TransformStreamDefaultSourcePullAlgorithm"
60686167 id="transform-stream-default-source-pull"> TransformStreamDefaultSourcePullAlgorithm(|stream|)</dfn>
@@ -7118,9 +7217,10 @@ reason.
71187217<div algorithm="create a TransformStream">
71197218 To <dfn export for="TransformStream" lt="set up|setting up">set up</dfn> a
71207219 newly-[=new|created-via-Web IDL=] {{TransformStream}} |stream| given an algorithm <dfn export
7121- for="TransformStream/set up"><var> transformAlgorithm</var></dfn> and an optional algorithm <dfn
7122- export for="TransformStream/set up"><var> flushAlgorithm</var></dfn> , perform the following steps.
7123- |transformAlgorithm| and, if given, |flushAlgorithm|, may return a promise.
7220+ for="TransformStream/set up"><var> transformAlgorithm</var></dfn> , an optional algorithm <dfn
7221+ export for="TransformStream/set up"><var> flushAlgorithm</var></dfn> , and an optional algorithm <dfn
7222+ export for="TransformStream/set up"><var> cancelAlgorithm</var></dfn> , perform the following steps.
7223+ |transformAlgorithm| and, if given, |flushAlgorithm| and |cancelAlgorithm|, may return a promise.
71247224
71257225 1. Let |writableHighWaterMark| be 1.
71267226 1. Let |writableSizeAlgorithm| be an algorithm that returns 1.
@@ -7136,12 +7236,18 @@ reason.
71367236 null otherwise. If this throws an exception |e|, return [=a promise rejected with=] |e|.
71377237 1. If |result| is a {{Promise}} , then return |result|.
71387238 1. Return [=a promise resolved with=] undefined.
7239+ 1. Let |cancelAlgorithmWrapper| be an algorithm that runs these steps given a value |reason|:
7240+ 1. Let |result| be the result of running |cancelAlgorithm| given |reason|, if |cancelAlgorithm|
7241+ was given, or null otherwise. If this throws an exception |e|, return
7242+ [=a promise rejected with=] |e|.
7243+ 1. If |result| is a {{Promise}} , then return |result|.
7244+ 1. Return [=a promise resolved with=] undefined.
71397245 1. Let |startPromise| be [=a promise resolved with=] undefined.
71407246 1. Perform ! [$InitializeTransformStream$] (|stream|, |startPromise|, |writableHighWaterMark|,
71417247 |writableSizeAlgorithm|, |readableHighWaterMark|, |readableSizeAlgorithm|).
71427248 1. Let |controller| be a [=new=] {{TransformStreamDefaultController}} .
71437249 1. Perform ! [$SetUpTransformStreamDefaultController$] (|stream|, |controller|,
7144- |transformAlgorithmWrapper|, |flushAlgorithmWrapper|).
7250+ |transformAlgorithmWrapper|, |flushAlgorithmWrapper|, |cancelAlgorithmWrapper| ).
71457251
71467252 Other specifications should be careful when constructing their
71477253 <i> [=TransformStream/set up/transformAlgorithm=] </i> to avoid [=in parallel=] reads from the given
0 commit comments