Skip to content

Commit cdffad6

Browse files
authored
Discuss async/parallel processing of written/transformed chunks
See WICG/serial#165. This ends up adding two pieces of advice: * One about how producers should wait on the promise returned by writer.write(), and how underlying sinks and transformers can use their promise return values to control that. * One about how specification authors should avoid reading from chunks in parallel.
1 parent eb1769c commit cdffad6

File tree

1 file changed

+37
-3
lines changed

1 file changed

+37
-3
lines changed

index.bs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@ spec:infra; type:dfn; text:list
1919
spec:html; type:dfn; text:entangle
2020
spec:html; type:dfn; text:message port post message steps
2121
spec:html; type:dfn; text:port message queue
22-
# TODO: remove these once whatwg/html#7414 is merged
23-
spec:websockets; type:interface; text:WebSocket
24-
spec:websockets; type:attribute; text:bufferedAmount; for:WebSocket
2522
</pre>
2623

2724
<pre class="anchors">
@@ -34,6 +31,7 @@ urlPrefix: https://tc39.es/ecma262/; spec: ECMASCRIPT
3431
text: ArrayBuffer; url: #sec-arraybuffer-objects
3532
text: DataView; url: #sec-dataview-objects
3633
text: Number; url: #sec-ecmascript-language-types-number-type
34+
text: SharedArrayBuffer; url: #sec-sharedarraybuffer-objects
3735
text: Uint8Array; url: #sec-typedarray-objects
3836
text: %Object.prototype%; url: #sec-properties-of-the-object-prototype-object
3937
type: dfn
@@ -4032,6 +4030,12 @@ callback UnderlyingSinkAbortCallback = Promise<undefined> (optional any reason);
40324030
its previous value, only increasing to signal the desire for more chunks once the write
40334031
succeeds.
40344032

4033+
<p>Finally, the promise potentially returned by this function is used to ensure that <a
4034+
href="#write-mutable-chunks">well-behaved</a> [=producers=] do not attempt to mutate the
4035+
[=chunk=] before it has been fully processed. (This is not guaranteed by any specification
4036+
machinery, but instead is an informal contract between [=producers=] and the [=underlying
4037+
sink=].)
4038+
40354039
<dt><dfn dict-member for="UnderlyingSink" lt="close">close()</dfn></dt>
40364040
<dd>
40374041
<p>A function that is called after the [=producer=] signals, via
@@ -4333,6 +4337,11 @@ following table:
43334337
<p>Note that what "success" means is up to the [=underlying sink=]; it might indicate simply that
43344338
the [=chunk=] has been accepted, and not necessarily that it is safely saved to its ultimate
43354339
destination.
4340+
4341+
<p id="write-mutable-chunks">If <var ignore>chunk</var> is mutable, [=producers=] are advised to
4342+
avoid mutating it after passing it to {{WritableStreamDefaultWriter/write()}}, until after the
4343+
promise returned by {{WritableStreamDefaultWriter/write()}} settles. This ensures that the
4344+
[=underlying sink=] receives and processes the same value that was passed in.
43364345
</dl>
43374346

43384347
<div algorithm>
@@ -5463,6 +5472,11 @@ callback TransformerTransformCallback = Promise<undefined> (any chunk, Transform
54635472
success or failure of the transformation. A rejected promise will error both the readable and
54645473
writable sides of the transform stream.
54655474

5475+
<p>The promise potentially returned by this function is used to ensure that <a
5476+
href="#write-mutable-chunks">well-behaved</a> [=producers=] do not attempt to mutate the [=chunk=]
5477+
before it has been fully transformed. (This is not guaranteed by any specification machinery, but
5478+
instead is an informal contract between [=producers=] and the [=transformer=].)
5479+
54665480
<p>If no {{Transformer/transform|transform()}} method is supplied, the identity transform is
54675481
used, which enqueues chunks unchanged from the writable side to the readable side.
54685482

@@ -6925,6 +6939,15 @@ for="ReadableStream">locked</dfn> if ! [$IsReadableStreamLocked$](|stream|) retu
69256939
|writeAlgorithm|, |closeAlgorithmWrapper|, |abortAlgorithmWrapper|, |highWaterMark|,
69266940
|sizeAlgorithm|).
69276941

6942+
Other specifications should be careful when constructing their
6943+
<i>[=WritableStream/set up/writeAlgorithm=]</i> to avoid [=in parallel=] reads from the given
6944+
[=chunk=], as such reads can violate the run-to-completion semantics of JavaScript. To avoid this,
6945+
they can make a synchronous copy or transfer of the given value, using operations such as
6946+
[$StructuredSerializeWithTransfer$], [=get a copy of the bytes held by the buffer source=], or
6947+
<a for="ArrayBuffer" lt="transfer">transferring an `ArrayBuffer`</a>. An exception is when the
6948+
[=chunk=] is a {{SharedArrayBuffer}}, for which it is understood that parallel mutations are a fact
6949+
of life.
6950+
69286951
<div class="example" id="example-set-up-ws">
69296952
Creating a {{WritableStream}} from other specifications is thus a two-step process, like so:
69306953

@@ -6936,6 +6959,8 @@ for="ReadableStream">locked</dfn> if ! [$IsReadableStreamLocked$](|stream|) retu
69366959
directly on the [=this=] value inside their constructor steps.</p>
69376960
</div>
69386961

6962+
<hr>
6963+
69396964
The following definitions must only be used on {{WritableStream}} instances initialized via the
69406965
above [=WritableStream/set up=] algorithm:
69416966

@@ -7021,6 +7046,15 @@ reason.
70217046
1. Perform ! [$SetUpTransformStreamDefaultController$](|stream|, |controller|,
70227047
|transformAlgorithmWrapper|, |flushAlgorithmWrapper|).
70237048

7049+
Other specifications should be careful when constructing their
7050+
<i>[=TransformStream/set up/transformAlgorithm=]</i> to avoid [=in parallel=] reads from the given
7051+
[=chunk=], as such reads can violate the run-to-completion semantics of JavaScript. To avoid this,
7052+
they can make a synchronous copy or transfer of the given value, using operations such as
7053+
[$StructuredSerializeWithTransfer$], [=get a copy of the bytes held by the buffer source=], or
7054+
<a for="ArrayBuffer" lt="transfer">transferring an `ArrayBuffer`</a>. An exception is when the
7055+
[=chunk=] is a {{SharedArrayBuffer}}, for which it is understood that parallel mutations are a fact
7056+
of life.
7057+
70247058
<div class="example" id="example-set-up-ts">
70257059
Creating a {{TransformStream}} from other specifications is thus a two-step process, like so:
70267060

0 commit comments

Comments
 (0)