Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Early draft of WritableStream "Design Philosophy" section #718

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -2568,6 +2568,45 @@ nothrow>ReadableByteStreamControllerShouldCallPull ( <var>controller</var> )</h4
writeRandomBytesForever(myWritableStream).catch(e => console.error("Something broke", e));
</code></pre>
</div>

<h3 id="ws-design-of-the-state-machine">Design Of The State Machine</h3>

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Needs to be marked non-normative)

<p>In addition to the principles for streams in general, a number of additional considerations have informed the design of
the WritableStream state machine.

<p>Some of these design decisions improve predictability, ease-of-use, and safety for developers at the expense of
making implementations more complex.

<ul>
<li><p>Only one sink method can ever be executing at a time.
<li><p>Sink methods are treated as atomic. A new sink method will never be called until the Promise from the previous
one has resolved. Most changes to the internal state do not take effect until any in-flight sink method has completed.
<li><p>Exception: If something has happened that will error the stream, for example writer.abort() has been called, then
new calls to writer.write() will start failing immediately. There's no user benefit in waiting for the current operation
to complete before informing the user that writer.write() has failed.
<li><p>The writer.ready promise and the value of writer.desiredSize reflect whether a write() performed right
now would be effective.
<ul>
<li>They will change even while a sink method is in-flight. writer.ready will reject as soon as new
calls to writer.write() will start failing. writer.desiredSize will change to null at the same time.
<div class=note>Because promises are dispatched asynchronously, the state can still change between
writer.ready becoming fulfilled and write() being called.</div>
<li>The value of writer.desiredSize decreases synchronously with every call to writer.write(). This implies that
the queueing strategy's size() function is executed synchronously.
</ul>
<li><p>The writer.closed promise and the promises returned by writer.close() and writer.abort() do not resolve or
reject until no sink methods are executing and no further sink methods will be executed.
<ul>
<li>If the user of the WritableStream wants to retry using the same underlying file, etc., it is important to
have confidence that all other operations have ceased.
<li>This principle also applies to the ReadableStream pipeTo() method.
</ul>
<li><p>Promises fulfill in consistent order. In particular, writer.ready always resolves before writer.closed, even
in cases where both are fulfilling in reaction to the same occurrence.
<li>Queued calls to writer methods such as write() are not cancelled when writer.releaseLock() is called. This makes
them easy to use in a "fire and forget" style.
</ul>

<h3 id="ws-class" interface lt="WritableStream">Class <code>WritableStream</code></h3>

<h4 id="ws-class-definition">Class Definition</h4>
Expand Down