1. 序論
~INFORMATIVE~web~platformの相当部分は、~streaming~data上に築かれている: すなわち,~dataは、全部を記憶域~内に読取することなく,増分的な方式fで、作成され, 処理され, 消費される。 Streams 標準は、そのような~streaming~dataを作成したり, それを~interface化するための,共通的~APIの集合を供する — それは `可読~stream$, `可書~stream$, `形式変換~stream$ として具体化される。 ◎ Large swathes of the web platform are built on streaming data: that is, data that is created, processed, and consumed in an incremental fashion, without ever reading all of it into memory. The Streams Standard provides a common set of APIs for creating and interfacing with such streaming data, embodied in readable streams, writable streams, and transform streams.
これらの~APIは、低level入出力~primitiveに効率的に対応付けられるよう,設計されている — 適切な所では~byte~stream用に特化することも含めて。 それは、複数の~streamからなる`~pipe鎖$を容易に組立てることや, `読取器$/`書込器$を介して直に利用することを可能にする。 それはまた、`背圧$と~queuingを自動的に供するよう,設計されている。 ◎ These APIs have been designed to efficiently map to low-level I/O primitives, including specializations for byte streams where appropriate. They allow easy composition of multiple streams into pipe chains, or can be used directly via readers and writers. Finally, they are designed to automatically provide backpressure and queuing.
この標準は、~web~platformを成す各~部品が,自身の~streaming~dataを公開するために利用できるような、基本的な~stream~primitiveを供する。 例えば `FETCH$r は、 `Response$I 本体を `ReadableStream$C ~instanceとして公開する。 より一般的には、~platformは、~streamへの抽象化を待っている ~streamingに満ちている: ~multimedia~stream, ~file~stream, 大域~obj間の通信, 等々… — すべてを記憶域~内に~bufferして,一度に処理する代わりに、~dataを増分的に処理できることから より便益が得られるような。 Streams Standard は、これらの~stream用の土台を供して,開発者たちに公開することにより、次の様な利用~事例を可能化する: ◎ This standard provides the base stream primitives which other parts of the web platform can use to expose their streaming data. For example, [FETCH] exposes Response bodies as ReadableStream instances. More generally, the platform is full of streaming abstractions waiting to be expressed as streams: multimedia streams, file streams, inter-global communication, and more benefit from being able to process data incrementally instead of buffering it all into memory and processing it in one go. By providing the foundation for these streams to be exposed to developers, the Streams Standard enables use cases like:
- ~video~effect: 形式変換~streamを通して~pipeすることで, 可読~video~streamに対し実時間に~effectを適用する。 ◎ Video effects: piping a readable video stream through a transform stream that applies effects in real time.
- 解凍: ~file~streamを形式変換~streamを通すように~pipeすることで, .tgz ~archiveの~fileを選択的に解凍する — 利用者が画像の展示を~scrollするのに伴って,それらを `img$e 要素に転換する。 ◎ Decompression: piping a file stream through a transform stream that selectively decompresses files from a .tgz archive, turning them into img elements as the user scrolls through an image gallery.
- 画像の復号-処理: HTTP 応答~streamを,[ ~byte列を~bitmap~dataに復号する,形式変換~stream ]を通してから[ ~bitmapを PNG に翻訳する別の形式変換 ]を通すように~pipeする。 ~service-workerの `fetch$et ~hookの内側に~installした場合、開発者は 新たな画像~形式を透過的に~polyfillできるようになる。 `SERVICE-WORKERS$r ◎ Image decoding: piping an HTTP response stream through a transform stream that decodes bytes into bitmap data, and then through another transform that translates bitmaps into PNGs. If installed inside the fetch hook of a service worker, this would allow developers to transparently polyfill new image formats. [SERVICE-WORKERS]
ここに述べる~APIを利用すれば、~Web開発者は,[ ~platformが供するものと同じ~APIを備えるような,自前の~stream ]も作成できる — 他の開発者は、~platformが供する~streamと, ~libraryから給される~streamとを,透過的に組立てることが可能になる。 ここに述べる~APIは、すべての~streamを統一化するための抽象化を供して、このような仕方で,この[ 共有され, 組立可能な~interface ]の周りで成長する~ecosystemを促進させる。 ◎ Web developers can also use the APIs described here to create their own streams, with the same APIs as those provided by the platform. Other developers can then transparently compose platform-provided streams with those supplied by libraries. In this way, the APIs described here provide unifying abstraction for all streams, encouraging an ecosystem to grow around these shared and composable interfaces.
【この訳に固有の表記規約】
この訳の,~algoや定義の記述に利用されている各種記号( ε, ~LET, ~IF, ~THROW, 等々)の意味や定義の詳細は、~SYMBOL_DEF_REFを~~参照されたし。
尚、この仕様~自身も~~末尾に自前の表記規約を備えていることに注意。
2. ~model
`~chunk@ とは、~stream[ へ書込される/から読取される ]ような,単独の~data片である。 それは,どのような型にもなり得る — ~streamは、型が互いに異なる~chunkたちを包含し得る。 ~chunkは、所与の~streamにおける不可分な~data単位にならないことも多い — 例えば,~byte~streamは、単独の~byte列の代わりに,それぞれが[ 16 KiB の `Uint8Array$I ]であるような~chunk列を包含することもある。 ◎ A chunk is a single piece of data that is written to or read from a stream. It can be of any type; streams can even contain chunks of different types. A chunk will often not be the most atomic unit of data for a given stream; for example a byte stream might contain chunks consisting of 16 KiB Uint8Arrays, instead of single bytes.
2.1. 可読~stream
`可読~stream@ ( `readable stream^en )は、そこから読取できるような,~dataの源を表現する。 言い換えれば、~dataは,可読~streamから ~~湧き出る。 可読~streamは、具体的には, `ReadableStream$C ~classの~instanceである。 ◎ A readable stream represents a source of data, from which you can read. In other words, data comes out of a readable stream. Concretely, a readable stream is an instance of the ReadableStream class.
可読~streamは,任意の挙動を伴わせて作成し得るが、ほとんどの可読~streamは、[ `下層~源@ ( `underlying source^en )と~~呼ばれる,より低levelな入出力~源 ]を包装する。 下層~源には、 2 種の型,`~push源$と`~pull源$がある。 ◎ Although a readable stream can be created with arbitrary behavior, most readable streams wrap a lower-level I/O source, called the underlying source. There are two types of underlying source: push sources and pull sources.
`~push源@ は、要請の有無にかかわらず,~dataを~pushしてくるような`下層~源$である。 それは、~dataの流れを 静止させる/再開させる ための仕組みを供することもある。 ~push源の例には,~TCP~socketがある — そこでは、~dataは~OS~levelから, ~TCP窓~sizeを変更することで制御し得るような~rateで,絶えず~pushされ続ける。 ◎ Push sources push data at you, whether or not you are listening for it. They may also provide a mechanism for pausing and resuming the flow of data. An example push source is a TCP socket, where data is constantly being pushed from the OS level, at a rate that can be controlled by changing the TCP window size.
`~pull源@ は、~dataを得るためには要請を要するような`下層~源$である。 ~dataは、同期的に可用になることもあれば(例: ~OSの記憶域~bufferに保持されている場合),非同期的に可用になることもある(例:~diskからの読取を要する場合)。 ~pull源の例には,~file~handleがある — そこでは、特定の所在へ~seekして,特定の量を読取する。 ◎ Pull sources require you to request data from them. The data may be available synchronously, e.g. if it is held by the operating system’s in-memory buffers, or asynchronously, e.g. if it has to be read from disk. An example pull source is a file handle, where you seek to specific locations and read specific amounts.
可読~streamは、両~型の源を,統一的な~interfaceの背後に包装するように,設計されている。 ~web開発者により作成される~stream用の源については、その実装の詳細は[ `ReadableStream()$rs 構築子に渡された, 一定の~method, ~propを伴う~obj ]により供される。 ◎ Readable streams are designed to wrap both types of sources behind a single, unified interface. For web developer–created streams, the implementation details of a source are provided by an object with certain methods and properties that is passed to the ReadableStream() constructor.
`~chunk$たちは、`下層~源$から,~streamの中へ~enqueueされる。 ~chunkたちは、~streamの~public~interfaceを介して — 特に、~streamの `getReader()$rs ~methodを用いて獲得した,`可読~stream読取器$を用いて — 一度に一個ずつ読取できる。 ◎ Chunks are enqueued into the stream by the stream’s underlying source. They can then be read one at a time via the stream’s public interface, in particular by using a readable stream reader acquired using the stream’s getReader() method.
可読~streamから その~public~interfaceを利用して読取する~codeは、 `消費器@ ( `consumer^en )と呼ばれている。 ◎ Code that reads from a readable stream using its public interface is known as a consumer.
消費器は、 `cancel()$rs ~methodを用いて,可読~streamを `取消す@ ( `cancel^en する)能も持つ。 これは、[ 消費器が~streamへの関心を失った ]こと,および[ 即時に~streamを~closeして, ~queueされた`~chunk$たちは捨てて, `下層~源$に取消の仕組みがあればそれを実行する ]ことを指示する。 ◎ Consumers also have the ability to cancel a readable stream, using its cancel() method. This indicates that the consumer has lost interest in the stream, and will immediately close the stream, throw away any queued chunks, and execute any cancellation mechanism of the underlying source.
消費器は,また、 `tee()$rs ~methodを用いて,可読~streamを `二叉化-@ する( `tee^en する†)こともできる。 これは、~streamを`~lock$して,それ以上 直に利用できなくする一方で、 `分岐@ ( `branch^en )と呼ばれる,独立に消費される 2 個の新たな~streamを作成する。 ◎ Consumers can also tee a readable stream using its tee() method. This will lock the stream, making it no longer directly usable; however, it will create two new streams, called branches, which can be consumed independently.
【† “tee する” という呼称は、 CUI における tee コマンドの “tee” — T 字型 分岐の “T” — に由来すると見られる。 】
~byte列を表現するような~streamに対しては、`可読~stream$の拡張~versionが供される — それは特に、複製を最小限にして,~byte列を効率的に取扱うためにある。 そのような可読~stream用の`下層~源$は、 `下層~byte源@ とも呼ばれる。 `下層~源$が`下層~byte源$でもあるような`可読~stream$は、 `可読~byte~stream@ とも呼ばれる。 可読~byte~streamの消費器は、~streamの `getReader()$rs ~methodを用いて,`~BYOB読取器$を獲得できる。 ◎ For streams representing bytes, an extended version of the readable stream is provided to handle bytes efficiently, in particular by minimizing copies. The underlying source for such a readable stream is called an underlying byte source. A readable stream whose underlying source is an underlying byte source is sometimes called a readable byte stream. Consumers of a readable byte stream can acquire a BYOB reader using the stream’s getReader() method.
2.2. 可書~stream
`可書~stream@ ( `writable stream^en )は、そこへ書込できるような,~dataの行先を表現する。 言い換えれば、~dataは 可書~streamへ~~流れ込む。 可書~streamは、具体的には, `WritableStream$C ~classの~instanceである。 ◎ A writable stream represents a destination for data, into which you can write. In other words, data goes in to a writable stream. Concretely, a writable stream is an instance of the WritableStream class.
可読~streamと相似的に、ほとんどの可書~streamも, `下層~槽@ ( `underlying sink^en )と呼ばれる より低levelな入出力~槽を包装する。 可書~streamは、一連の書込を~queueして,下層~槽に一個ずつ送達することにより、下層~槽の複雑さの一部を抽象化して見えなくするように働く。 ◎ Analogously to readable streams, most writable streams wrap a lower-level I/O sink, called the underlying sink. Writable streams work to abstract away some of the complexity of the underlying sink, by queuing subsequent writes and only delivering them to the underlying sink one by one.
`~chunk$たちは、その~public~interfaceを介して,~streamへ書込され、一度に一個ずつ~streamの`下層~槽$に渡される。 ~web開発者により作成される~stream用の槽については、その実装の詳細は[ `WritableStream()$ws 構築子に渡された, 一定の~method, ~propを伴う~obj ]により供される。 ◎ Chunks are written to the stream via its public interface, and are passed one at a time to the stream’s underlying sink. For web developer-created streams, the implementation details of the sink are provided by an object with certain methods that is passed to the WritableStream() constructor.
可書~streamの中へ,その~public~interfaceを利用して書込する~codeは、 `生産器@ ( `producer^en )と呼ばれている。 ◎ Code that writes into a writable stream using its public interface is known as a producer.
`生産器$には、 `abort()$ws ~methodを用いて,可書~streamを `中止-@ ( `abort^en )する能もある。 これは、[ 生産器が,何か不具合があると確信したこと, したがって 以降の書込は継続されるべきでないこと ]を指示する。 これは、`下層~槽$からの合図がなくとも,~streamを~error状態に置くことに加え,~streamの`内部~queue$内にある すべての書込を破棄する。 ◎ Producers also have the ability to abort a writable stream, using its abort() method. This indicates that the producer believes something has gone wrong, and that future writes should be discontinued. It puts the stream in an errored state, even without a signal from the underlying sink, and it discards all writes in the stream’s internal queue.
2.3. 形式変換~stream
`形式変換~stream@ ( `transform stream^en )は、~streamの~pair — `可書~側@ と称される`可書~stream$, `可読~側@ と称される`可読~stream$ — からなる。 当の形式変換~stream特有の方式で,可書~側へ書込される結果、新たな~dataが可読~側から読取されて可用になる。 ◎ A transform stream consists of a pair of streams: a writable stream, known as its writable side, and a readable stream, known as its readable side. In a manner specific to the transform stream in question, writes to the writable side result in new data being made available for reading from the readable side.
具体的には、[ `writable^m, `readable^m ]両~propを伴うような どの~objも、形式変換~streamとして~~働き得る。 しかしながら、標準の `TransformStream$C ~classが,適正に連絡された そのような~pairをずっと容易に作成する。 それは、[ 遂行される特定の形式変換n用の~algoを定義する, `形式変換器@ ( `transformer^en )~obj ]を包装する。 ~web開発者により作成される~stream用の`形式変換器$については、その実装の詳細は[ `TransformStream()$ts 構築子に渡された, 一定の~method, ~propを伴う~obj ]により供される。 ◎ Concretely, any object with a writable property and a readable property can serve as a transform stream. However, the standard TransformStream class makes it much easier to create such a pair that is properly entangled. It wraps a transformer, which defines algorithms for the specific transformation to be performed. For web developer–created streams, the implementation details of a transformer are provided by an object with certain methods and properties that is passed to the TransformStream() constructor.
`~identity形式変換~stream@ は、形式変換~streamの一種であり,`可書~側$に書込された`~chunk$をそのまま`可読~側$に送り込む。 これは、様々な局面で有用になる。 `形式変換器$~objに `transform()$tf ~methodが不在のときの既定では、 `TransformStream$C 構築子は,~identity形式変換~streamを作成することになる。 ◎ An identity transform stream is a type of transform stream which forwards all chunks written to its writable side to its readable side, without any changes. This can be useful in a variety of scenarios. By default, the TransformStream constructor will create an identity transform stream, when no transform() method is present on the transformer object.
形式変換~streamになり得る例: ◎ Some examples of potential transform streams include:
- GZIP 圧縮器 — 未圧縮の~byte列が そこへ書込され,圧縮-済み~byte列が そこから読取される; ◎ A GZIP compressor, to which uncompressed bytes are written and from which compressed bytes are read;
- ~video復号器 — 符号化された~byte列が そこへ書込され, 未圧縮の~video~frameたちが そこから読取される ◎ A video decoder, to which encoded bytes are written and from which uncompressed video frames are read;
- ~text復号器 — ~byte列が そこへ書込され, 文字列たちが そこから読取される; ◎ A text decoder, to which bytes are written and from which strings are read;
- CSV-to-JSON 変換器 — CSV ~fileをなす各~行を表現する文字列たちが そこへ書込され、対応する~JS~objたちが そこから読取される。 ◎ A CSV-to-JSON converter, to which strings representing lines of a CSV file are written and from which corresponding JavaScript objects are read.
2.4. ~pipe鎖と背圧
~streamたちは首に,互いに `~pipe@ して利用される。 可読~streamは、 `pipeTo()$rs ~methodを用いて,直に可書~streamに~pipeすることも、その~~前に `pipeThrough()$rs ~methodを用いて,いくつかの形式変換~streamを通してから ~pipeすることもできる。 ◎ Streams are primarily used by piping them to each other. A readable stream can be piped directly to a writable stream, using its pipeTo() method, or it can be piped through one or more transform streams first, using its pipeThrough() method.
この仕方で互いに~pipeされた一連の~streamは、 `~pipe鎖@ ( `pipe chain^en )と呼ばれる。 ~pipe鎖の先頭にある可読~streamの`下層~源$を `元の源@ ( `original source^en )と呼び、末尾にある可書~streamの`下層~槽$を `最終~槽@ ( `ultimate sink^en )と呼ぶ。 ◎ A set of streams piped together in this way is referred to as a pipe chain. In a pipe chain, the original source is the underlying source of the first readable stream in the chain; the ultimate sink is the underlying sink of the final writable stream in the chain.
`~pipe鎖$が構築されたなら、それを通して[ `~chunk$たちをどの~~程度 高速に流すべきかについての合図 ]を伝播することになる。 鎖のある段が~chunkをまだ受容できない場合、~pipe鎖を通して後方へ, 最終的に元の源まで,合図が伝播され、元の源に ~chunkの生産-を止めるよう伝えることになる。 この,[ 鎖がどの~~程度 高速に~chunkを処理できるかに則って,元の源からの流れを正常化する処理 ]は、 `背圧@ ( `backpressure^en )と呼ばれる。 ◎ Once a pipe chain is constructed, it will propagate signals regarding how fast chunks should flow through it. If any step in the chain cannot yet accept chunks, it propagates a signal backwards through the pipe chain, until eventually the original source is told to stop producing chunks so fast. This process of normalizing flow from the original source according to how fast the chain can process chunks is called backpressure.
具体的には、`元の源$が~dataを流す~rateは, %controller.`desiredSize$rsdc (または %byteController.`desiredSize$rbsc )から与えられる値に則って調整できる。 この値は、`最終~槽$に対応している %writer.`desiredSize$dw から導出され,最終~槽への`~chunk$の書込みが完遂する度に更新される。 `pipeTo()$rs ~methodは、この鎖を自動的に構築するために利用され,この情報が`~pipe鎖$を遡って伝播することを確保する。 ◎ Concretely, the original source is given the controller.desiredSize (or byteController.desiredSize) value, and can then adjust its rate of data flow accordingly. This value is derived from the writer.desiredSize corresponding to the ultimate sink, which gets updated as the ultimate sink finishes writing chunks. The pipeTo() method used to construct the chain automatically ensures this information propagates back through the pipe chain.
可読~streamが`二叉化-$されたときは、その両`分岐$からの`背圧$合図は,両~分岐とも読取できないときには 集成された上で、元の~streamの`下層~源$へ送信されることになる。 ◎ When teeing a readable stream, the backpressure signals from its two branches will aggregate, such that if neither branch is read from, a backpressure signal will be sent to the underlying source of the original stream.
~pipeすることにより,[ 可読, 可書 ]~streamは、`~lock$され,~pipe演算の間は操作できなくされる。 これにより,実装は、[ 中間的な~queueの多くを迂回して,~dataを下層~源から下層~槽へ直に~~運び続ける ]などの重要な最適化を,遂行できるようになる。 ◎ Piping locks the readable and writable streams, preventing them from being manipulated for the duration of the pipe operation. This allows the implementation to perform important optimizations, such as directly shuttling data from the underlying source to the underlying sink while bypassing many of the intermediate queues.
2.5. 内部~queueと~queuing策
可読~stream, 可書~stream のいずれも, `内部~queue@ ( `internal queue^en )を保守し,類似する目的に利用する。 可読~streamの内部~queueは、[ `下層~源$により~enqueueされたが,`消費器$からはまだ読取されていない ]ような`~chunk$たちを包含する。 可書~streamの内部~queueは、[ `生産器$により~streamに書込され,承認されたが、まだ`下層~槽$により処理されていない ]ような`~chunk$たちを包含する。 ◎ Both readable and writable streams maintain internal queues, which they use for similar purposes. In the case of a readable stream, the internal queue contains chunks that have been enqueued by the underlying source, but not yet read by the consumer. In the case of a writable stream, the internal queue contains chunks which have been written to the stream by the producer, but not yet processed and acknowledged by the underlying sink.
`~queuing策@ ( `queuing strategy^en )とは、~streamが[ 自身の`内部~queue$の状態に基づいて,`背圧$を どのように合図すべきか ]を決定するような,~objである。 ~queuing策は、各`~chunk$に~sizeをあてがい,[ ~queue内のすべての~chunkの合計~size ]と[ `限界水位@ ( `high-water mark^en )と呼ばれる,指定された~number ]とを比較する。 結果の差分 ~EQ [ 限界水位 − 合計~size ]は、 `~streamの内部~queueの残り~size@ ( `desired size to fill the stream’s queue^en )を決定するために利用される。 ◎ A queuing strategy is an object that determines how a stream should signal backpressure based on the state of its internal queue. The queuing strategy assigns a size to each chunk, and compares the total size of all chunks in the queue to a specified number, known as the high water mark. The resulting difference, high water mark minus total size, is used to determine the desired size to fill the stream’s queue.
可読~streamにおいては、下層~源は,この残り~sizeを[ ~chunk生成を減速させる背圧~合図 ]に利用できる — 残り~sizeを 0 以上に保とうとするために。 可書~streamにおいては、生産器は,類似するように挙動できる — 残り~sizeが負になる前に書込を避けるために。 ◎ For readable streams, an underlying source can use this desired size as a backpressure signal, slowing down chunk generation so as to try to keep the desired size above or at zero. For writable streams, a producer can behave similarly, avoiding writes that would cause the desired size to go negative.
具体的には、 `highWaterMark^m ~propを伴うような どの~JS~objも,~web開発者により作成される~stream用の~queuing策を与える。 ~byte~stream用の `highWaterMark^m は常に~byte単位になる。 他の~stream用の既定は`~chunk$単位になるが、~queuing策~obj内に[ 所与の~chunkに対し その~sizeを返す `size()^m 関数 ]を含ませれば, `highWaterMark^m に任意の浮動小数点~単位を指定することを許可できる。 ◎ Concretely, a queuing strategy for web developer–created streams is given by any JavaScript object with a highWaterMark property. For byte streams the highWaterMark always has units of bytes. For other streams the default unit is chunks, but a size() function can be included in the strategy object which returns the size for a given chunk. This permits the highWaterMark to be specified in arbitrary floating-point units.
~queuing策の単純な例には、各`~chunk$ごとに~size 1 をあてがい,`限界水位$は一定数にするものが挙げられる。 これは、~streamが背圧を適用する前に[ 可読~stream内に~enqueueできる/ 可書~streamに書込できる ]~chunk数は,その一定数までに限られることを意味する。 ◎ A simple example of a queuing strategy would be one that assigns a size of one to each chunk, and has a high water mark of three. This would mean that up to three chunks could be enqueued in a readable stream, or three chunks written to a writable stream, before the streams are considered to be applying backpressure.
~JSにおいては、そのような策は、 `{ highWaterMark: 3, size() { return 1; }}^c のように手動で書くことも, 組込みの `CountQueuingStrategy$C ~classを用いて `new CountQueuingStrategy({ highWaterMark: 3 })^c のように書くこともできる。 ◎ In JavaScript, such a strategy could be written manually as { highWaterMark: 3, size() { return 1; }}, or using the built-in CountQueuingStrategy class, as new CountQueuingStrategy({ highWaterMark: 3 }).
2.6. ~lock法
`可読~stream読取器@ または略して 読取器 ( `reader^en )とは、`可読~stream$から直に`~chunk$を読取できるようにする~objである。 読取器がない下で,`消費器$が遂行できることは、可読~stream上の高level演算 — ~streamを`取消す$か, または 可読~streamから可書~streamへ`~pipeする$ — に限られる。 読取器は、~streamの `getReader()$rs ~methodを介して獲得される。 ◎ A readable stream reader, or simply reader, is an object that allows direct reading of chunks from a readable stream. Without a reader, a consumer can only perform high-level operations on the readable stream: canceling the stream, or piping the readable stream to a writable stream. A reader is acquired via the stream’s getReader() method.
`可読~byte~stream$には、 2 種の型の読取器[ `既定の読取器@ と `~BYOB読取器@ ]を配給する能がある。 ~BYOB( “`Bring Your Own Buffer^en” — “開発者が~bufferを給する” )読取器は、開発者から給される~bufferの中へ読取できるようにして,~dataの複製を最小限にする。 可読~byte~stream以外の可読~streamが配給できるのは、既定の読取器に限られる。 既定の読取器は, `ReadableStreamDefaultReader$C ~classの~instanceである一方、~BYOB読取器は, `ReadableStreamBYOBReader$C ~classの~instanceである。 ◎ A readable byte stream has the ability to vend two types of readers: default readers and BYOB readers. BYOB ("bring your own buffer") readers allow reading into a developer-supplied buffer, thus minimizing copies. A non-byte readable stream can only vend default readers. Default readers are instances of the ReadableStreamDefaultReader class, while BYOB readers are instances of ReadableStreamBYOBReader.
同様に、 `可書~stream書込器@ または略して 書込器 ( `writer^en )とは、`可書~stream$に直に`~chunk$を書込できるようにする~objである。 書込器がない下で,`生産器$が遂行できることは、可書~stream上の高level演算 — ~streamを中止するか, 可読~streamから可書~streamへ`~pipeする$ — に限られる。 書込器は、 `WritableStreamDefaultWriter$C ~classで表現される。 ◎ Similarly, a writable stream writer, or simply writer, is an object that allows direct writing of chunks to a writable stream. Without a writer, a producer can only perform the high-level operations of aborting the stream or piping a readable stream to the writable stream. Writers are represented by the WritableStreamDefaultWriter class.
注記: これらの高level演算は、実際には[ 読取器/書込器 ]を裏で利用する。 ◎ Under the covers, these high-level operations actually use a reader or writer themselves.
所与の[ 可読/可書 ]~streamを利用している[ 読取器/書込器 ]がある間は、他のどの[ 読取器/書込器 ]も,その~streamを利用できない。 このことを,~streamは `~lockされて@ いる( `is locked^en )と言い、[ 読取器/書込器 ]は `作動中@ ( `active^en )と言う。 この状態は、[ %readableStream.`locked$rs / %writableStream.`locked$ws ]~propを用いて決定できる。 ◎ A given readable or writable stream only has at most one reader or writer at a time. We say in this case the stream is locked, and that the reader or writer is active. This state can be determined using the readableStream.locked or writableStream.locked properties.
[ 読取器/書込器 ]は、その~lockを `解放-@ ( `release^en )する能力も持つ。 それにより,[ 読取器/書込器 ]は`作動中$でなくなり、他の[ 読取器/書込器 ]は,当の~streamの~lockを獲得できるようになる。 これは、[ %defaultReader.`releaseLock()$dr, %byobReader.`releaseLock()$byob, %writer.`releaseLock()$dw ]いずれか適切な~methodを介して行える。 ◎ A reader or writer also has the capability to release its lock, which makes it no longer active, and allows further readers or writers to be acquired. This is done via the defaultReader.releaseLock(), byobReader.releaseLock(), or writer.releaseLock() method, as appropriate.
3. 可読~stream
3.1. 可読~streamの用法
可読~streamを消費する最も単純な仕方は、単純にそれを`可書~stream$へ`~pipeする$ことである。 これにより,その`背圧$が尊重されるようになり、(書込みでも読取りでも)~errorが生じれば`~pipe鎖$を通して伝播される: ◎ The simplest way to consume a readable stream is to simply pipe it to a writable stream. This ensures that backpressure is respected, and any errors (either writing or reading) are propagated through the chain:
%readableStream.pipeTo(%writableStream) .then(() => console.log(`すべての~dataは成功裡に書込されました^l)) .catch(%e => console.error(`何かまずいことが起きたようです^l, %e));
可読~streamからの各 新たな~chunkを,単純に改めたいと欲するならば、それを,[ その目的に~customに作成した,新たな`可書~stream$ ]へ`~pipeする$こともできる: ◎ If you simply want to be alerted of each new chunk from a readable stream, you can pipe it to a new writable stream that you custom-create for that purpose:
%readableStream.pipeTo(new WritableStream({ write(%chunk) { console.log(`~chunkが受信されました^l, %chunk); }, close() { console.log(`すべての~dataを成功裡に読取しました^l); }, abort(%e) { console.error(`何かまずいことが起きたようです^l, %e); } }));
~~自前の `write()$snk 実装から~promiseを返すことにより、可読~streamに向けて`背圧$を合図できる。 ◎ By returning promises from your write() implementation, you can signal backpressure to the readable stream.
可読~streamは、通例的に,可書~streamへ~pipeするために利用されるが、直に読取することもできる — `読取器$を獲得してから,その `read()^m ~methodを利用して ~chunkの連なりを取得することにより。 例えば,次の~codeは、~stream内の次回の`~chunk$が可用なら,その~logをとる: ◎ Although readable streams will usually be used by piping them to a writable stream, you can also read them directly by acquiring a reader and using its read() method to get successive chunks. For example, this code logs the next chunk in the stream, if available:
const %reader = %readableStream.getReader(); %reader.read().then( ({ %value, %done }) => { if (%done) { console.log(`~streamはすでに~closeされています^l); } else { console.log(%value); } }, %e => console.error(`~streamに~errorが生じたので読取できません^l, %e) );
この~methodは、~streamを より手動的に読取するとき — 主に~library作者にとって、[ `~pipe$する/`二叉化-$する ]ことから供されるものを超えるような,~stream上に新たな高level演算を築くとき — に有用になる。 ◎ This more manual method of reading a stream is mainly useful for library authors building new high-level operations on streams, beyond the provided ones of piping and teeing.
上の例では,可読~streamの`既定の読取器$の利用を示したが、~streamが`可読~byte~stream$である場合は,それ用の`~BYOB読取器$も獲得できる — それにより、複製を避けるよう,~buffer割当てを より精確に制御できるようになる。 例えば次の~codeは、~streamから最初の 1024 ~byteを,単独の記憶域~bufferの中に読取する: ◎ The above example showed using the readable stream’s default reader. If the stream is a readable byte stream, you can also acquire a BYOB reader for it, which allows more precise control over buffer allocation in order to avoid copies. For example, this code reads the first 1024 bytes from the stream into a single memory buffer:
const %reader = readableStream.getReader({ mode: `byob^l }); let %startingAB = new ArrayBuffer(1024); readInto(%startingAB) .then(%buffer => console.log(`最初の 1024 ~byte:^l, %buffer)) .catch(%e => console.error(`何かまずいことが起きたようです^l, %e)); function readInto(%buffer, %offset = 0) { if (%offset === %buffer.byteLength) { return Promise.resolve(%buffer); } const %view = new Uint8Array(%buffer, %offset, %buffer.byteLength - %offset); return %reader.read(%view).then(%newView => { return readInto(%newView.buffer, %offset + %newView.byteLength); }); }
ここで重要なことは、~~最終的な %buffer 値は %startingAB と異なるが、それら(および すべての中間的~buffer)は,裏では同じ記憶域の割当てを共有することである。 ~bufferは、毎回 新たな `ArrayBuffer$I ~objに 転送される。 %newView は、各種~propが次のように設定された,新たな `Uint8Array$I になる ⇒# `buffer^m ~SET 当の `ArrayBuffer$I ~obj; `byteOffset^m ~SET 書込された~byte列の~offset; `byteLength^m ~SET 書込された~byte数 ◎ An important thing to note here is that the final buffer value is different from the startingAB, but it (and all intermediate buffers) shares the same backing memory allocation. At each step, the buffer is transferred to a new ArrayBuffer object. The newView is a new Uint8Array, with that ArrayBuffer object as its buffer property, the offset that bytes were written to as its byteOffset property, and the number of bytes that were written as its byteLength property.
3.2. `ReadableStream^C ~class
`ReadableStream$C ~classは、`可読~stream$の一般~概念を実体化する~instanceである。 それは、どのような`~chunk$型にも適応-可能であり,[ `下層~源$から給されたが, まだ消費器から読取されていない~data ]を保ち続けるための内部~queueを保守する。 ◎ The ReadableStream class is a concrete instance of the general readable stream concept. It is adaptable to any chunk type, and maintains an internal queue to keep track of data supplied by the underlying source but not yet read by any consumer.
3.2.1. ~class定義
~INFORMATIVE`ReadableStream$C ~classは、 `ECMASCRIPT$r 風の構文で書くならば,次のようになる: ◎ If one were to write the ReadableStream class in something close to the syntax of [ECMASCRIPT], it would look like
class ReadableStream { `constructor$rs(%underlyingSource = {}, %strategy = {}) get `locked()$rs `cancel(reason)$rs `getReader()$rs `pipeThrough({ writable, readable }, options)$rs `pipeTo(dest, { preventClose, preventAbort, preventCancel } = {})$rs `tee()$rs }
3.2.2. 内部~slot
`ReadableStream$C の各~instanceは、次の一覧に述べる各種 内部~slotを伴って作成される: ◎ Instances of ReadableStream are created with the internal slots described in the following table:
内部~slot | 説明0(参考) |
---|---|
[[disturbed]] | 真偽~flag — ~streamから何か読取されたか, ~streamが取消されたとき, ~true に設定される。 ◎ A boolean flag set to true when the stream has been read from or canceled |
[[readableStreamController]] | [ この~streamの状態と~queueを制御する能 ]を伴って作成される[ `ReadableStreamDefaultController$C または `ReadableByteStreamController$C ]。 `IsReadableStream$A による~brand検査-時にも利用される。 ◎ A ReadableStreamDefaultController or ReadableByteStreamController created with the ability to control the state and queue of this stream; also used for the IsReadableStream brand check |
[[reader]] | この~streamを`~lock$している`読取器$ — `ReadableStreamDefaultReader$C または `ReadableStreamBYOBReader$C — の~instanceが[ あれば それ / なければ ~undefined ]。 ◎ A ReadableStreamDefaultReader or ReadableStreamBYOBReader instance, if the stream is locked to a reader, or undefined if it is not |
[[state]] | 内部的に利用される,~streamの現在の状態を表す文字列 — 次のいずれか: `readable^l, `closed^l, `errored^l ◎ A string containing the stream’s current state, used internally; one of "readable", "closed", or "errored" |
[[storedError]] | ~streamが どのように失敗したかを指示する値 — ~errorした~streamに対し演算しようと試行しているときに、失敗~事由か例外として与えられることになる。 ◎ A value indicating how the stream failed, to be given as a failure reason or exception when trying to operate on an errored stream |
3.2.3. `new ReadableStream(underlyingSource = {}, strategy = {})^rs
%underlyingSource 引数は — `§下層~源~API$にて述べるように — `下層~源$を表現する。 ◎ The underlyingSource argument represents the underlying source, as described in §3.2.4 Underlying source API.
%strategy 引数は — `§~queuing策~API$にて述べるように — ~streamの`~queuing策$を表現する。 供されなかった場合の既定の挙動は、`限界水位$ 1 にされた `CountQueuingStrategy$C と同じになる。 ◎ The strategy argument represents the stream’s queuing strategy, as described in §6.1.1 The queuing strategy API. If it is not provided, the default behavior will be the same as a CountQueuingStrategy with a high water mark of 1.
- ! `InitializeReadableStream$A( ~this ) ◎ Perform ! InitializeReadableStream(this).
- %size ~LET ? `GetV$A( %strategy, `size^l ) ◎ Let size be ? GetV(strategy, "size").
- %highWaterMark ~LET ? `GetV$A( %strategy, `highWaterMark^l ) ◎ Let highWaterMark be ? GetV(strategy, "highWaterMark").
- %type ~LET ? `GetV$A( %underlyingSource, `type^l ) ◎ Let type be ? GetV(underlyingSource, "type").
- %typeString ~LET ? `ToString$A( %type ) ◎ Let typeString be ? ToString(type).
-
~IF[ %typeString ~EQ `bytes^l ]: ◎ If typeString is "bytes",
- ~IF[ %size ~NEQ ~undefined ] ⇒ ~THROW `RangeError^b ◎ If size is not undefined, throw a RangeError exception.
- ~IF[ %highWaterMark ~EQ ~undefined ] ⇒ %highWaterMark ~LET `0^b ◎ If highWaterMark is undefined, let highWaterMark be 0.
- %highWaterMark ~SET ? `ValidateAndNormalizeHighWaterMark$A( %highWaterMark ) ◎ Set highWaterMark to ? ValidateAndNormalizeHighWaterMark(highWaterMark).
- ? `SetUpReadableByteStreamControllerFromUnderlyingSource$A( ~this, %underlyingSource, %highWaterMark ) ◎ Perform ? SetUpReadableByteStreamControllerFromUnderlyingSource(this, underlyingSource, highWaterMark).
-
~ELIF %type ~EQ ~undefined : ◎ Otherwise, if type is undefined,
- %sizeAlgorithm ~LET ? `MakeSizeAlgorithmFromSizeFunction$A( %size ) ◎ Let sizeAlgorithm be ? MakeSizeAlgorithmFromSizeFunction(size).
- ~IF[ %highWaterMark ~EQ ~undefined ] ⇒ %highWaterMark ~SET `1^b ◎ If highWaterMark is undefined, let highWaterMark be 1.
- %highWaterMark ~SET ? `ValidateAndNormalizeHighWaterMark$A( %highWaterMark ) ◎ Set highWaterMark to ? ValidateAndNormalizeHighWaterMark(highWaterMark).
- ? `SetUpReadableStreamDefaultControllerFromUnderlyingSource$A( ~this, %underlyingSource, %highWaterMark, %sizeAlgorithm ) ◎ Perform ? SetUpReadableStreamDefaultControllerFromUnderlyingSource(this, underlyingSource, highWaterMark, sizeAlgorithm).
- ~ELSE ⇒ ~THROW `RangeError^b ◎ Otherwise, throw a RangeError exception.
3.2.4. 下層~源~API
~INFORMATIVE`ReadableStream()$rs 構築子は、 1 個目の引数に[ `下層~源$を表現している~JS~obj ]を受容する。 そのような~objには、次に挙げる~propを包含させられる: ◎ The ReadableStream() constructor accepts as its first argument a JavaScript object representing the underlying source. Such objects can contain any of the following properties:
- `start(controller)@src
- この関数は、 `ReadableStream$C を作成する間に即時に~callされる。 ◎ A function that is called immediately during creation of the ReadableStream.
- これは、概して,次のために利用される: 関連する~event~listenerを設定しておくことにより,`~push源$を適応させる(その例は、`§下層~push源を伴う可読~stream(背圧~supportなし)$に見れる)/ `~pull源$への~accessを獲得する(その例は、`§下層~pull源を伴う可読~stream$に見れる)。 ◎ Typically this is used adapt a push source by setting up relevant event listeners, as in the example of §8.1 A readable stream with an underlying push source (no backpressure support), or to acquire access to a pull source, as in §8.4 A readable stream with an underlying pull source.
- この設定しておく処理が非同期的になる場合、この関数は,成否を合図する~promiseを返すようにすることもできる — 却下される~promiseは、~streamを~errorにすることになる。 投出された例外は、 `ReadableStream()$rs 構築子により再~投出されることになる。 ◎ If this setup process is asynchronous, it can return a promise to signal success or failure; a rejected promise will error the stream. Any thrown exceptions will be re-thrown by the ReadableStream() constructor.
- `pull(controller)@src
- この関数は、~chunkたちが成す~streamの`内部~queue$が満杯でなくなり次第 — すなわち、~queueの`~streamの内部~queueの残り~size$ ~GT 0 になり次第 — ~callされる。 一般に,~queueは`限界水位$に達するまで(すなわち,`~streamの内部~queueの残り~size$が ~LTE 0 になるまで),繰返し~callされることになる。 ◎ A function that is called whenever the stream’s internal queue of chunks becomes not full, i.e. whenever the queue’s desired size becomes positive. Generally, it will be called repeatedly until the queue reaches its high water mark (i.e. until the desired size becomes non-positive).
- `~push源$に対しては、この関数は,静止された流れを再開するために利用され得る(その例は、`§下層~push源を伴う可読~stream(背圧~supportあり)$に見れる)。 `~pull源$に対しては、~streamの中へ~enqueueする新たな`~chunk$を獲得するために利用される(その例は、`§下層~pull源を伴う可読~stream$に見れる)。 ◎ For push sources, this can be used to resume a paused flow, as in §8.2 A readable stream with an underlying push source and backpressure support. For pull sources, it is used to acquire new chunks to enqueue into the stream, as in §8.4 A readable stream with an underlying pull source.
- この関数は、 `start()$src が成功裡に完了するまでは,~callされない。 加えて,繰返し~callされるのは、それが[ 1 個以上の~chunkを~enqueueするか, ~BYOB要請を充足する ]場合に限られる — 何もしない `pull()$src 実装は、断続的に~callされることはない。 ◎ This function will not be called until start() successfully completes. Additionally, it will only be called repeatedly if it enqueues at least one chunk or fulfills a BYOB request; a no-op pull() implementation will not be continually called.
- この関数が~promiseを返す場合、その~promiseが充足されるまでは,再度~callされることはない(~promiseが却下された場合、~streamは~errorにされることになる)。 これは、主に,~pull源の事例で利用される。 — そこでは、返される~promiseは新たな~chunkを獲得する処理を表現する。 例外を投出した場合、却下される~promiseを返すのと同じに扱われる。 ◎ If the function returns a promise, then it will not be called again until that promise fulfills. (If the promise rejects, the stream will become errored.) This is mainly used in the case of pull sources, where the promise returned represents the process of acquiring a new chunk. Throwing an exception is treated the same as returning a rejected promise.
- `cancel(reason)@src
- この関数は、~streamが`消費器$により[ %stream.`cancel()$rs / %defaultReader.`cancel()$dr / %byobReader.`cancel()$byob ]を介して`取消され$次第,~callされる。 その引数は、消費器がそれらの~methodに渡したのと同じ値をとる。 ◎ A function that is called whenever the consumer cancels the stream, via stream.cancel(), defaultReader.cancel(), or byobReader.cancel(). It takes as its argument the same value as was passed to those methods by the consumer.
- 加えて,可読~streamは、`~pipeする$間に,一定の条件~下で取消されることもある — 詳細は、 `pipeTo()$rs ~methodの定義を見よ。 ◎ Readable streams can additionally be canceled under certain conditions during piping; see the definition of the pipeTo() method for more details.
- この関数は,どの~streamにおいても、一般に,下層~資源への~accessを解放するために利用される — 例えば`§下層~push源を伴う可読~stream(背圧~supportなし)$を見よ。 ◎ For all streams, this is generally used to release access to the underlying resource; see for example §8.1 A readable stream with an underlying push source (no backpressure support).
- この~shutdown処理が非同期的になる場合、この関数は,成否を合図する~promiseを返すようにすることもできる: その結果は ~callした `cancel()^c ~methodの返値を介して通信される。 加えて、却下される~promiseは、~streamを — そのまま~closeさせずに — ~errorにすることになる。 例外を投出した場合、却下される~promiseを返すのと同じに扱われる。 ◎ If the shutdown process is asynchronous, it can return a promise to signal success or failure; the result will be communicated via the return value of the cancel() method that was called. Additionally, a rejected promise will error the stream, instead of letting it close. Throwing an exception is treated the same as returning a rejected promise.
- `type@src (~byte~stream用に限る) ◎ type (byte streams only)
- `bytes^l に設定すれば、構築される `ReadableStream$C は`可読~byte~stream$であることを合図できる。 これは、[ 結果の `ReadableStream$C が — その `getReader()$rs ~methodを介して — `~BYOB読取器$を成功裡に配給-可能にする ]ことを確保する。 また、下に与える[ `start()$src / `pull()$src ]~methodに渡される %controller 引数にも影響する。 ◎ Can be set to "bytes" to signal that the constructed ReadableStream is a readable byte stream. This ensures that the resulting ReadableStream will successfully be able to vend BYOB readers via its getReader() method. It also affects the controller argument passed to the start() and pull() methods; see below.
- 可読~byte~streamを設定しておく方法の例は — 異なる制御器~interfaceを利用することも含め — `§下層~push源を伴う可読~byte~stream(背圧~supportなし)$に見れる。 ◎ For an example of how to set up a readable byte stream, including using the different controller interface, see §8.3 A readable byte stream with an underlying push source (no backpressure support).
- [ `bytes^l, `undefined^b ]以外の値に設定した場合、 `ReadableStream()$rs 構築子は例外を投出することになる。 ◎ Setting any value other than "bytes" or undefined will cause the ReadableStream() constructor to throw an exception.
- `autoAllocateChunkSize@src (~byte~stream用に限る) ◎ autoAllocateChunkSize (byte streams only)
- 正整数に設定すれば、[ 実装が、下層~源の~code用に,書込~用の~bufferを自動的に割当てる ]ようにできる。 この事例では、`消費器$が`既定の読取器$を利用しているときは、~stream実装は,所与の~sizeの `ArrayBuffer$I を自動的に割当てる — [ 消費器は`~BYOB読取器$を利用していた ]かのように,常に %controller.`byobRequest$rbsc が在るようにするため。 ◎ Can be set to a positive integer to cause the implementation to automatically allocate buffers for the underlying source code to write into. In this case, when a consumer is using a default reader, the stream implementation will automatically allocate an ArrayBuffer of the given size, so that controller.byobRequest is always present, as if the consumer was using a BYOB reader.
- これは,一般に、[ 既定の読取器を利用する消費器 ]を取扱うために必要な~code量も減らすために利用される — 次の 2 つを比較されたし ⇒# 自動割当てを伴わない`§下層~push源を伴う可読~byte~stream(背圧~supportなし)$, 自動割当てを伴う`§下層~pull源を伴う可読~byte~stream$ ◎ This is generally used to cut down on the amount of code needed to handle consumers that use default readers, as can be seen by comparing §8.3 A readable byte stream with an underlying push source (no backpressure support) without auto-allocation to §8.5 A readable byte stream with an underlying pull source with auto-allocation.
[ `start()$src / `pull()$src ]~methodに渡される %controller 引数の型は, `type$src ~optionの値に依存し、それに応じて ⇒# ~undefined (または省略された)ならば `ReadableStreamDefaultController$C になる / `bytes^l ならば `ReadableByteStreamController$C になる ◎ The type of the controller argument passed to the start() and pull() methods depends on the value of the type option. If type is set to undefined (including via omission), controller will be a ReadableStreamDefaultController. If it’s set to "bytes", controller will be a ReadableByteStreamController.
3.2.5. `ReadableStream^C ~prototypeの各種~prop
3.2.5.1. `get locked^rs
`locked^rs 取得子は、可読~streamが読取器に`~lockされて$いるかどうかを返す。 ◎ The locked getter returns whether or not the readable stream is locked to a reader.
- ~IF[ ! `IsReadableStream$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStream(this) is false, throw a TypeError exception.
- ~RET ! `IsReadableStreamLocked$A( ~this ) ◎ Return ! IsReadableStreamLocked(this).
3.2.5.2. `cancel(reason)^rs
`cancel()^rs ~methodは、~streamを`取消-$して,[ `消費器$が~streamへの関心を失った ]ことを合図する。 給された %reason 引数は、下層~源の `cancel()$src ~methodに~~渡される — 利用されるとは限らないが。 ◎ The cancel method cancels the stream, signaling a loss of interest in the stream by a consumer. The supplied reason argument will be given to the underlying source’s cancel() method, which might or might not use it.
- ~IF[ ! `IsReadableStream$A( ~this ) ~EQ ~false ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsReadableStream(this) is false, return a promise rejected with a TypeError exception.
- ~IF[ ! `IsReadableStreamLocked$A( ~this ) ~EQ ~true ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
- ~RET ! `ReadableStreamCancel$A( ~this, %reason ) ◎ Return ! ReadableStreamCancel(this, reason).
3.2.5.3. `getReader({ mode } = {})^rs
`getReader()^rs ~methodは、 %mode ~optionに指定される型の読取器を作成して返すと同時に,~streamを その新たな読取器に`~lock$する。 ~streamが`~lockされて$いる間は、`解放-$されるまで,他の読取器は~lockを獲得できなくなる。 ◎ The getReader method creates a reader of the type specified by the mode option and locks the stream to the new reader. While the stream is locked, no other reader can be acquired until this one is released.
この機能性は、[[ ~streamを,それ全体として消費する能 ]を欲するような,抽象化 ]を創出するときに,とりわけ有用になる。 利用者は、~stream用の読取器を取得することにより,[ 他から[ 読取が差挟まれたり,~streamが取消される ]ことにより,自身による抽象化が干渉される ]ことがないことを確保できる。 ◎ This functionality is especially useful for creating abstractions that desire the ability to consume a stream in its entirety. By getting a reader for the stream, you can ensure nobody else can interleave reads with yours or cancel the stream, which would interfere with your abstraction.
%mode ~EQ ~undefined の場合、この~methodは `既定の読取器$( `ReadableStreamDefaultReader$C の~instance)を作成する。 この読取器は、読取器の `read()$dr ~methodを介して,~streamから個々の`~chunk$を直に読取する能を供する。 ◎ When mode is undefined, the method creates a default reader (an instance of ReadableStreamDefaultReader). The reader provides the ability to directly read individual chunks from the stream via the reader’s read() method.
%mode ~EQ `byob^l の場合、この~methodは `~BYOB読取器$( `ReadableStreamBYOBReader$C の~instance)を作成する。 この特色機能は、`可読~byte~stream$ — すなわち、 “開発者が~bufferを給する” 読取りを取扱う能を 特に備えるように構築された~stream — 上でのみ働く。 この読取器は、読取器の `read()$byob ~methodを介して,[ ~streamから開発者から給された~bufferの中へ 個々の`~chunk$を直に読取する能 ]を供し、~bufferの割当てをより精確に制御できるようにする。 ◎ When mode is "byob", the getReader method creates a BYOB reader (an instance of ReadableStreamBYOBReader). This feature only works on readable byte streams, i.e. streams which were constructed specifically with the ability to handle "bring your own buffer" reading. The reader provides the ability to directly read individual chunks from the stream via the reader’s read() method, into developer-supplied buffers, allowing more precise control over allocation.
- ~IF[ ! `IsReadableStream$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStream(this) is false, throw a TypeError exception.
- ~IF[ %mode ~EQ ~undefined ] ⇒ ~RET ? `AcquireReadableStreamDefaultReader$A( ~this ) ◎ If mode is undefined, return ? AcquireReadableStreamDefaultReader(this).
- %mode ~SET ? `ToString$A(%mode). ◎ Set mode to ? ToString(mode).
- ~IF[ %mode ~EQ `byob^l ] ⇒ ~RET ? `AcquireReadableStreamBYOBReader$A( ~this ) ◎ If mode is "byob", return ? AcquireReadableStreamBYOBReader(this).
- ~THROW `RangeError^b ◎ Throw a RangeError exception.
読取器を利用すれば便益を得られるであろう抽象化の例として、可読~stream全体を`~chunk$の配列として記憶域の中に読取するように設計された,次のような関数がある: ◎ An example of an abstraction that might benefit from using a reader is a function like the following, which is designed to read an entire readable stream into memory as an array of chunks.
function readAllChunks(%readableStream) { const %reader = %readableStream.getReader(); const %chunks = []; return pump(); function pump() { return %reader.read().then(({ %value, %done }) => { if (%done) { return %chunks; } %chunks.push(%value); return pump(); }); } }
最初に 読取器を得ることで、読取器を排他的に利用していることに注意。 これにより、他の消費器は,[ ~chunkを読取したり, ~streamを`取消す$ことにより,~streamに干渉する ]ことはできなくなる。 ◎ Note how the first thing it does is obtain a reader, and from then on it uses the reader exclusively. This ensures that no other consumer can interfere with the stream, either by reading chunks or by canceling the stream.
3.2.5.4. `pipeThrough({ writable, readable }, options)^rs
`pipeThrough()^rs ~methodは、[
`形式変換~stream$(または,他の
{ %writable, %readable }
~pair)を通して,この`可読~stream$を`~pipeする$
]ための,簡便かつ連鎖-可能な仕方を供する。
それは 単純に、給された~pairの可書~側へ~streamを~pipeして,更なる利用のために 可読~側を返す。
◎
The pipeThrough method provides a convenient, chainable way of piping this readable stream through a transform stream (or any other { writable, readable } pair). It simply pipes the stream into the writable side of the supplied pair, and returns the readable side for further use.
一般に,~streamが~pipeされている間は、他の消費器が読取器を獲得できないように,~streamは`~lock$される。 ◎ Piping a stream will generally lock it for the duration of the pipe, preventing any other consumer from acquiring a reader.
この~methodは、その ~this 値が `ReadableStream$C ~objであることを要求しない点で,意図的に汎化してある。 また、その[ %writable / %readable ]引数が[ `WritableStream$C / `ReadableStream$C ]の~instanceであることも要求しない。 ◎ This method is intentionally generic; it does not require that its this value be a ReadableStream object. It also does not require that its writable argument be a WritableStream instance, or that its readable argument be a ReadableStream instance.
-
~IF[ %writable ~EQ ~undefined ]~OR[ %readable ~EQ ~undefined ] ⇒ ~THROW `TypeError^b ◎ If writable is undefined or readable is undefined, throw a TypeError exception indicating that undefined values are not permitted.
~errorを~debugし易くするため、ここでの ~undefined 値は,特別に許可されない — さもなければ、 `rs.pipeThrough(writable, readable)^m は何もせず黙することになるので。 他の受け渡す値については、 `pipeThrough()$rs は~~関知しない。 ◎ undefined is special-cased here to make it easier to debug errors such as rs.pipeThrough(writable, readable) which otherwise would silently do nothing. pipeThrough() is otherwise agnostic about the values that it passes through.
- %promise ~LET ? `Invoke$A( ~this, `pipeTo^l, « %writable, %options » ) ◎ Let promise be ? Invoke(this, "pipeTo", « writable, options »).
- ~IF[ `Type$A( %promise ) ~EQ `Object^b ]~AND[ %promise は [[PromiseIsHandled]] 内部~slotを持つ ] ⇒ %promise.[[PromiseIsHandled]] ~SET ~true ◎ If Type(promise) is Object and promise has a [[PromiseIsHandled]] internal slot, set promise.[[PromiseIsHandled]] to true.
- ~RET %readable ◎ Return readable.
`pipeThrough(transform, options)$rs を利用して`~pipe鎖$を構築する典型~例: ◎ A typical example of constructing pipe chain using pipeThrough(transform, options) would look like
%httpResponseBody .pipeThrough(%decompressorTransform) .pipeThrough(%ignoreNonImageFilesTransform) .pipeTo(%mediaGallery);
3.2.5.5. `pipeTo(dest, { preventClose, preventAbort, preventCancel } = {})^rs
`pipeTo()^rs ~methodは、この`可読~stream$を,所与の`可書~stream$に`~pipeする$。 ~piping処理における 種々の~error条態の下での挙動は、渡される %options ( `{ ... }^m )により~custom化できる。 この~methodは、~piping処理が[ 成功裡に完了したときに充足される/ 何らかの~errorに遭遇したときに却下される ]ような~promiseを返す。 ◎ The pipeTo method pipes this readable stream to a given writable stream. The way in which the piping process behaves under various error conditions can be customized with a number of passed options. It returns a promise that fulfills when the piping process completes successfully, or rejects if any errors were encountered.
~streamが~pipeされている間は、他の消費器が読取器を獲得できないように,~streamを`~lock$する。 ◎ Piping a stream will lock it for the duration of the pipe, preventing any other consumer from acquiring a reader.
源の`可読~stream$ %source, 行先の`可書~stream$ %dest における[ ~error/~closure ]は、次に従って伝播する: ◎ Errors and closures of the source and destination streams propagate as follows:
- %source における~errorは、[ `preventAbort^m が~truthy ]でない限り, %dest を`中止-$することになる。 返される~promiseは,[ %source における~error, または %dest を中止する間に~errorが生じたなら それ ]で却下されることになる。 ◎ An error in the source readable stream will abort the destination writable stream, unless preventAbort is truthy. The returned promise will be rejected with the source’s error, or with any error that occurs during aborting the destination.
- %dest における~errorは、[ `preventAbort^m が~truthy ]でない限り, %source を`取消す$ことになる。 返される~promiseは,[ %dest における~error, または %source を取消す間に~errorが生じた場合は それ ]で却下されることになる。 ◎ An error in the destination writable stream will cancel the source readable stream, unless preventCancel is truthy. The returned promise will be rejected with the destination’s error, or with any error that occurs during canceling the source.
- %source が~closeしたときは、[ `preventClose^m ~EQ ~true ]でない限り, %dest も~closeさせることになる。 返される~promiseは、この処理が完了した時点で充足されることになる — ただし、行先を~closeしている間に~errorに遭遇した場合は、その~errorで却下されることになる。 ◎ When the source readable stream closes, the destination writable stream will be closed, unless preventClose is true. The returned promise will be fulfilled once this process completes, unless an error is encountered while closing the destination, in which case it will be rejected with that error.
- %dest が[ ~closeされ始めたとき / ~close中にある ]場合、[ `preventCancel^m ~EQ ~true ]でない限り, %source は`取消され$ることになる。 返される~promiseは,[ ~streamは~closeされたため~pipeするのに失敗したことを指示する~error, または %source を取消す間に生じた~error ]で却下されることになる。 ◎ If the destination writable stream starts out closed or closing, the source readable stream will be canceled, unless preventCancel is true. The returned promise will be rejected with an error indicating piping to a closed stream failed, or with any error that occurs during canceling the source.
- ~IF[ ! `IsReadableStream$A( ~this ) ~EQ ~false ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsReadableStream(this) is false, return a promise rejected with a TypeError exception.
- ~IF[ ! `IsWritableStream$A( %dest ) ~EQ ~false ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsWritableStream(dest) is false, return a promise rejected with a TypeError exception.
- %preventClose ~SET ! `ToBoolean$A( %preventClose ) ◎ Set preventClose to ! ToBoolean(preventClose),\
- %preventAbort ~SET ! `ToBoolean$A( %preventAbort ) ◎ set preventAbort to ! ToBoolean(preventAbort), and\
- %preventCancel ~SET ! `ToBoolean$A( %preventCancel ) ◎ set preventCancel to ! ToBoolean(preventCancel).
- ~IF[ ! `IsReadableStreamLocked$A( ~this ) ~EQ ~true ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
- ~IF[ ! `IsWritableStreamLocked$A( %dest ) ~EQ ~true ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsWritableStreamLocked(dest) is true, return a promise rejected with a TypeError exception.
- ~IF[ ! `IsReadableByteStreamController$A( ~this.[[readableStreamController]] ) ~EQ ~true ] ⇒ %reader ~LET ~UAの裁量で,次のいずれかを遂行した結果 ⇒# ! `AcquireReadableStreamBYOBReader$A( ~this ) / ! `AcquireReadableStreamDefaultReader$A( ~this ) ◎ If ! IsReadableByteStreamController(this.[[readableStreamController]]) is true, let reader be either ! AcquireReadableStreamBYOBReader(this) or ! AcquireReadableStreamDefaultReader(this), at the user agent’s discretion.
- ~ELSE ⇒ %reader ~LET ! `AcquireReadableStreamDefaultReader$A( ~this ) ◎ Otherwise, let reader be ! AcquireReadableStreamDefaultReader(this).
- %writer ~LET ! `AcquireWritableStreamDefaultWriter$A( %dest ) ◎ Let writer be ! AcquireWritableStreamDefaultWriter(dest).
- %shuttingDown ~LET ~false ◎ Let shuttingDown be false.
- %promise ~LET `新たな~promise$ ◎ Let promise be a new promise.
-
( %reader, %writer ) を用いて,`並列的$に 本当はそうでない — #905 を見よ — ~this から すべての`~chunk$を読取して %dest に書込する。 これが起こる正確な方式は、 ( 読取器, 書込器 ) が供する~lock法に因り,作者~codeからは観測できない。 よって,~UAには これを柔軟に行う余地があるが、利用される正確な~algoが何であれ,次の拘束が適用される: ◎ In parallel but not really; see #905, using reader and writer, read all chunks from this and write them to dest. Due to the locking provided by the reader and writer, the exact manner in which this happens is not observable to author code, and so there is flexibility in how this is done. The following constraints apply regardless of the exact algorithm used:
- ~public~APIは利用されては~MUST_NOT: — [ 読取り/書込み ]の間, および 以下に挙げる演算を遂行している間は、何かを改変-可能な~JSの[ 読取器, 書込器, ~stream~API ](すなわち,適切な~prototype上の各種~method)は、利用されては~MUST_NOT — ~streamは,直に操作され~MUST。 ◎ Public API must not be used: while reading or writing, or performing any of the operations below, the JavaScript-modifiable reader, writer, and stream APIs (i.e. methods on the appropriate prototypes) must not be used. Instead, the streams must be manipulated directly.
-
背圧は施行され~MUST — ~UAは: ◎ Backpressure must be enforced:
- `WritableStreamDefaultWriterGetDesiredSize$A( %writer ) の結果が[ 0 以下, または `null^b ]になる間は、 %reader から読取しては~MUST_NOT ◎ While WritableStreamDefaultWriterGetDesiredSize(writer) is ≤ 0 or is null, the user agent must not read from reader.
- %reader が`~BYOB読取器$である場合 ⇒ %reader から読取する~chunkの~sizeを決定するときには, `WritableStreamDefaultWriterGetDesiredSize$A( %writer ) を利用するべきである。 ◎ If reader is a BYOB reader, WritableStreamDefaultWriterGetDesiredSize(writer) should be used to determine the size of the chunks read from reader.
-
読取や書込は、背圧~合図~以外の理由で遅延されるべきでない。 ◎ Reads or writes should not be delayed for reasons other than these backpressure signals.
次回の 読取/書込 演算を続行する前に,各 書込が成功裡に完了するのを待機するような実装は、この推奨に違反する。 そのような実装では、 %dest の`内部~queue$は,常に高々 1 個の`~chunk$しか包含せず,役立たずになるので。 ◎ An implementation that waits for each write to successfully complete before proceeding to the next read/write operation violates this recommendation. In doing so, such an implementation makes the internal queue of dest useless, as it ensures dest always contains at most one queued chunk.
- ~shutdownは、活動を停止させ~MUST — %shuttingDown が ~true になって以降は、~UAは,それ以上 %reader からの読取を起動しては~MUST_NOT。 また、以下に述べるように,すでに読取された~chunkの書込のみを遂行し~MUST。 特に,~UAは、[ 読取/書込 ]を遂行する前に,以下の条件を検査し~MUST — それらは、即時に~shutdownに至らせることもあるので。 ◎ Shutdown must stop activity: if shuttingDown becomes true, the user agent must not initiate further reads from reader, and must only perform writes of already-read chunks, as described below. In particular, the user agent must check the below conditions before performing any reads or writes, since they might lead to immediate shutdown.
-
~error/~close状態は伝播され~MUST — 次に挙げる条件は順に適用され~MUST: ◎ Error and close states must be propagated: the following conditions must be applied in order.
-
~errorは前方へ伝播され~MUST — ~this.[[state]] ~EQ `errored^l のとき, または そうなったときは: ◎ Errors must be propagated forward: if this.[[state]] is or becomes "errored", then
- ~IF[ %preventAbort ~EQ ~false ] ⇒ `~shutdownする$( ~this.[[storedError]], 次を行う動作 ) ⇒ ! `WritableStreamAbort$A( %dest, ~this.[[storedError]] ) ◎ If preventAbort is false, shutdown with an action of ! WritableStreamAbort(dest, this.[[storedError]]) and with this.[[storedError]].
- ~ELSE ⇒ `~shutdownする$( ~this.[[storedError]], ε ) ◎ Otherwise, shutdown with this.[[storedError]].
-
~errorは後方へ伝播され~MUST — %dest.[[state]] ~EQ `errored^l のとき, または そうなったときは: ◎ Errors must be propagated backward: if dest.[[state]] is or becomes "errored", then
- ~IF[ %preventCancel ~EQ ~false ] ⇒ `~shutdownする$( %dest.[[storedError]], 次を行う動作 ) ⇒ ! `ReadableStreamCancel$A( ~this, %dest.[[storedError]] ) ◎ If preventCancel is false, shutdown with an action of ! ReadableStreamCancel(this, dest.[[storedError]]) and with dest.[[storedError]].
- ~ELSE ⇒ `~shutdownする$( %dest.[[storedError]], ε ) ◎ Otherwise, shutdown with dest.[[storedError]].
-
~closingは前方へ伝播され~MUST — ~this.[[state]] ~EQ `closed^l のとき, または そうなったときは: ◎ Closing must be propagated forward: if this.[[state]] is or becomes "closed", then
- ~IF[ %preventClose ~EQ ~false ] ⇒ `~shutdownする$( ε, 次を行う動作 ) ⇒ ! `WritableStreamDefaultWriterCloseWithErrorPropagation$A( %writer ) ◎ If preventClose is false, shutdown with an action of ! WritableStreamDefaultWriterCloseWithErrorPropagation(writer).
- ~ELSE ⇒ `~shutdownする$( ε, ε ) ◎ Otherwise, shutdown.
-
~closingは後方へ伝播され~MUST — [ ! `WritableStreamCloseQueuedOrInFlight$A( %dest ) ~EQ ~true ]~OR[ %dest.[[state]] ~EQ `closed^l ]のときは: ◎ Closing must be propagated backward: if ! WritableStreamCloseQueuedOrInFlight(dest) is true or dest.[[state]] is "closed", then
- ~Assert: [ 読取した/書込した ]`~chunk$はない ◎ Assert: no chunks have been read or written.
- %destClosed ~LET 新たな `TypeError^b ◎ Let destClosed be a new TypeError.
- ~IF[ %preventCancel ~EQ ~false ] ⇒ `~shutdownする$( %destClosed, 次を行う動作 ) ⇒ ! `ReadableStreamCancel$A( ~this, %destClosed ) ◎ If preventCancel is false, shutdown with an action of ! ReadableStreamCancel(this, destClosed) and with destClosed.
- ~ELSE ⇒ `~shutdownする$( %destClosed, ε ) ◎ Otherwise, shutdown with destClosed.
-
-
上のいずれかの要件/手続きにより, `~shutdownする@ よう請われたときは、所与の ( %error, %action ) に対し,次の下位手続きを遂行する: ◎ Shutdown with an action: if any of the above requirements ask to shutdown with an action action, optionally with an error originalError, then:
- ~IF[ %shuttingDown ~EQ ~true ] ⇒ ~RET ◎ If shuttingDown is true, abort these substeps.
- %shuttingDown ~SET ~true ◎ Set shuttingDown to true.
-
~IF[ %dest.[[state]] ~EQ `writable^l ]~AND[ ! `WritableStreamCloseQueuedOrInFlight$A( %dest ) ~EQ ~false ]: ◎ If dest.[[state]] is "writable" and ! WritableStreamCloseQueuedOrInFlight(dest) is false,
- ~IF[ 読取されたがまだ書込されていない`~chunk$はある ] ⇒ それらを %dest に書込する ◎ If any chunks have been read but not yet written, write them to dest.
- 読取されたすべての`~chunk$が書込されるまで(すなわち,対応する~promiseは決着するまで)待機する ◎ Wait until every chunk that has been read has been written (i.e. the corresponding promises have settled).
-
~IF[ %action ~EQ ε ]:
- `完結する$( %error )
- ~RET
-
%p ~LET %action を遂行した結果: ◎ Let p be the result of performing action.
- %p の`充足-時$には ⇒ `完結する$( %error ) ◎ Upon fulfillment of p, finalize, passing along originalError if it was given.
- 事由 %newError による %p の`却下-時$には ⇒ `完結する$( %newError ) ◎ Upon rejection of p with reason newError, finalize with newError.
【 この手続きは、原文では, 2 つに分けて記されているが( %action ~EQ ε の場合と 非 ε の場合)、表記の都合により この訳では一つに集約している。 】
◎ Shutdown: if any of the above requirements or steps ask to shutdown, optionally with an error error, then: • If shuttingDown is true, abort these substeps. • Set shuttingDown to true. • If dest.[[state]] is "writable" and ! WritableStreamCloseQueuedOrInFlight(dest) is false, •• If any chunks have been read but not yet written, write them to dest. •• Wait until every chunk that has been read has been written (i.e. the corresponding promises have settled). • Finalize, passing along error if it was given. -
`完結する@ 下位手続きは、所与の ( %error ) に対し,次を遂行する: ◎ Finalize: both forms of shutdown will eventually ask to finalize, optionally with an error error, which means to perform the following steps:
- ! `WritableStreamDefaultWriterRelease$A( %writer ) ◎ Perform ! WritableStreamDefaultWriterRelease(writer).
- ! `ReadableStreamReaderGenericRelease$A( %reader ) ◎ Perform ! ReadableStreamReaderGenericRelease(reader).
- ~IF[ %error ~NEQ ε ] ⇒ %error で %promise を`却下する$ ◎ If error was given, reject promise with error.
- ~ELSE ⇒ ~undefined で %promise を`解決する$ ◎ Otherwise, resolve promise with undefined.
- ~RET %promise ◎ Return promise.
注記: ここで遂行される種々の抽象~演算では,~objが作成され(~promiseを成すものが多い)、それらの~obj用には,通例的に`~realm$を指定することが要求される。 しかしながら,~lock中にあるので、それらの~objは 作者~codeからは観測され得ない。 そのようなわけで、それらの作成-時に利用する`~realm$が~~問題になることはない。 ◎ Various abstract operations performed here include object creation (often of promises), which usually would require specifying a realm for the created object. However, because of the locking, none of these objects can be observed by author code. As such, the realm used to create them does not matter.
3.2.5.6. `tee()^rs
`tee()^rs (二叉化-)~methodは、この可読~streamを`二叉化-$して、その結果の,[ それぞれが新たな `ReadableStream$C ~instanceである, 2 個の`分岐$ ]からなる~~長さ 2 の配列を返す。 ◎ The tee method tees this readable stream, returning a two-element array containing the two resulting branches as new ReadableStream instances.
~streamを二叉化すると,それを`~lock$し,他の消費器は読取器を獲得できなくなる。 ~streamを`取消す$ためには、結果の分岐を両者とも取消す — しかる後、この複合的な取消~事由が,~streamの`下層~源$まで伝播されることになる。 ◎ Teeing a stream will lock it, preventing any other consumer from acquiring a reader. To cancel the stream, cancel both of the resulting branches; a composite cancellation reason will then be propagated to the stream’s underlying source.
各~分岐~内で見える`~chunk$たちは 同じ~objになるので、~chunkが変異-可能な場合, 2 個の分岐~間で互いに干渉し合うことも許容されることに注意。 ◎ Note that the chunks seen in each branch will be the same object. If the chunks are not immutable, this could allow interference between the two branches.
- ~IF[ ! `IsReadableStream$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStream(this) is false, throw a TypeError exception.
- %branches ~LET ? `ReadableStreamTee$A( ~this, ~false ) ◎ Let branches be ? ReadableStreamTee(this, false).
- ~RET ! `CreateArrayFromList$A( %branches ) ◎ Return ! CreateArrayFromList(branches).
~streamの二叉化は、~streamを 2 個の独立な消費器から並列的に — おそらく異なる速度で — 読取させたいと望むときに最も有用になる。 例えば、[ ~disk上の~fileを表現している可書~stream %cacheEntry ]と, [ ~remote~serverへの~uploadを表現している別の可書~stream %httpRequestBody ]が与えられたとき、同じ可読~streamを,同時に両~行先へ~pipeすることもできる: ◎ Teeing a stream is most useful when you wish to let two independent consumers read from the stream in parallel, perhaps even at different speeds. For example, given a writable stream cacheEntry representing an on-disk file, and another writable stream httpRequestBody representing an upload to a remote server, you could pipe the same readable stream to both destinations at once:
const [%forLocal, %forRemote] = %readableStream.tee(); Promise.all([ %forLocal.pipeTo(%cacheEntry), %forRemote.pipeTo(%httpRequestBody) ]) .then(() => console.log( `~streamは ~cacheに保存され, ~uploadされました^l)) .catch(%e => console.error( `~cache時または~upload時に失敗しました: ^l, %e));
3.3.一般の可読~stream抽象~演算
以下の抽象~演算は、この仕様を成す大部分と違って,他の仕様からも 一般に有用になるよう意味されている — 単に,この仕様の各種~classの実装の一部としてではなく。 ◎ The following abstract operations, unlike most in this specification, are meant to be generally useful by other specifications, instead of just being part of the implementation of this spec’s classes.
3.3.1. `AcquireReadableStreamBYOBReader( stream )^A
この抽象~演算は、所与の~streamから`~BYOB読取器$を獲得したいと望むような,他の仕様から~callされる用途に意味されている。 ◎ This abstract operation is meant to be called from other specifications that may wish to acquire a BYOB reader for a given stream.
- ~RET ? `Construct$A( `ReadableStreamBYOBReader$C, « %stream » ) ◎ Return ? Construct(ReadableStreamBYOBReader, « stream »).
3.3.2. `AcquireReadableStreamDefaultReader( stream )^A
この抽象~演算は、所与の~streamから`既定の読取器$を獲得したいと望むような,他の仕様から~callされる用途に意味されている。 ◎ This abstract operation is meant to be called from other specifications that may wish to acquire a default reader for a given stream.
- ~RET ? `Construct$A( `ReadableStreamDefaultReader$C, « %stream » ) ◎ Return ? Construct(ReadableStreamDefaultReader, « stream »).
3.3.3. `CreateReadableStream( startAlgorithm, pullAlgorithm, cancelAlgorithm [, highWaterMark [, sizeAlgorithm ] ] )^A
この抽象~演算は、 `ReadableStream$C ~instanceを作成したいと望むような,他の仕様から~callされる用途に意味されている。
- [ %pullAlgorithm / %cancelAlgorithm ]は、~promiseを返す~algoで~MUST。
- %sizeAlgorithm は、給されるならば,`~chunk$~objを受容して ~numberを返す~algoで~MUST。
- %highWaterMark は、給されるならば,負でも `NaN^b でもない ~numberで~MUST。
注記: `CreateReadableStream$A は、給された %startAlgorithm が投出するとき, そのときに限り例外を投出する。 ◎ CreateReadableStream throws an exception if and only if the supplied startAlgorithm throws.
- ~IF[ %highWaterMark は渡されていない ] ⇒ %highWaterMark ~SET `1^b ◎ If highWaterMark was not passed, set it to 1.
- ~IF[ %sizeAlgorithm は渡されていない ] ⇒ %sizeAlgorithm ~SET `1^b を返す~algo ◎ If sizeAlgorithm was not passed, set it to an algorithm that returns 1.
- ~Assert: ! `IsNonNegativeNumber$A( %highWaterMark ) ~EQ ~true ◎ Assert: ! IsNonNegativeNumber(highWaterMark) is true.
- %stream ~LET `ObjectCreate$A( `ReadableStream$C の `prototype^c ~propの元の値 ) ◎ Let stream be ObjectCreate(the original value of ReadableStream's prototype property).
- ! `InitializeReadableStream$A( %stream ) ◎ Perform ! InitializeReadableStream(stream).
- %controller ~LET `ObjectCreate$A( `ReadableStreamDefaultController$C の `prototype^c ~propの元の値 ) ◎ Let controller be ObjectCreate(the original value of ReadableStreamDefaultController's prototype property).
- ? `SetUpReadableStreamDefaultController$A( %stream, %controller, %startAlgorithm, %pullAlgorithm, %cancelAlgorithm, %highWaterMark, %sizeAlgorithm ) ◎ Perform ? SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm).
- ~RET %stream ◎ Return stream.
3.3.4. `CreateReadableByteStream( startAlgorithm, pullAlgorithm, cancelAlgorithm [, highWaterMark [, autoAllocateChunkSize ] ] )^A
この抽象~演算は、型 "bytes" の `ReadableStream$C ~instanceを作成したいと望むような,他の仕様から~callされる用途に意味されている。
- [ %pullAlgorithm / %cancelAlgorithm ]は、~promiseを返す~algoで~MUST。
- %highWaterMark は、給されるならば,負でも `NaN^b でもない ~numberで~MUST。
- %autoAllocateChunkSize は、給されるならば,正整数で~MUST。
注記: `CreateReadableByteStream$A は、給された %startAlgorithm が投出するとき, そのときに限り例外を投出する。 ◎ CreateReadableByteStream throws an exception if and only if the supplied startAlgorithm throws.
- ~IF[ %highWaterMark は渡されていない ] ⇒ %highWaterMark ~SET `0^b ◎ If highWaterMark was not passed, set it to 0.
- ~IF[ %autoAllocateChunkSize は渡されていない ] ⇒ %autoAllocateChunkSize ~SET ~undefined ◎ If autoAllocateChunkSize was not passed, set it to undefined.
- ~Assert: ! `IsNonNegativeNumber$A( %highWaterMark ) ~EQ ~true ◎ Assert: ! IsNonNegativeNumber(highWaterMark) is true.
-
~IF[ %autoAllocateChunkSize ~NEQ ~undefined ]: ◎ If autoAllocateChunkSize is not undefined,
- ~Assert: ! `IsInteger$A( %autoAllocateChunkSize ) ~EQ ~true ◎ Assert: ! IsInteger(autoAllocateChunkSize) is true.
- ~Assert: %autoAllocateChunkSize ~GT 0 ◎ Assert: autoAllocateChunkSize is positive.
- %stream ~LET `ObjectCreate$A( `ReadableStream$C の `prototype^c ~propの元の値 ) ◎ Let stream be ObjectCreate(the original value of ReadableStream's prototype property).
- ! `InitializeReadableStream$A( %stream ) ◎ Perform ! InitializeReadableStream(stream).
- %controller ~LET `ObjectCreate$A( `ReadableByteStreamController$C の `prototype^c ~propの元の値 ) ◎ Let controller be ObjectCreate(the original value of ReadableByteStreamController's prototype property).
- ? `SetUpReadableByteStreamController$A( %stream, %controller, %startAlgorithm, %pullAlgorithm, %cancelAlgorithm, %highWaterMark, %autoAllocateChunkSize ) ◎ Perform ? SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, autoAllocateChunkSize).
- ~RET %stream ◎ Return stream.
3.3.5. `InitializeReadableStream( stream )^A
- %stream の ⇒# .[[state]] ~SET `readable^l, .[[reader]] ~SET ~undefined, .[[storedError]] ~SET ~undefined, .[[disturbed]] ~SET ~false ◎ Set stream.[[state]] to "readable". ◎ Set stream.[[reader]] and stream.[[storedError]] to undefined. ◎ Set stream.[[disturbed]] to false.
3.3.6. `IsReadableStream( x )^A
- ~IF[ `Type$A(%x) ~NEQ `Object^b ] ⇒ ~RET ~false ◎ If Type(x) is not Object, return false.
- ~IF[ %x は [[readableStreamController]] 内部~slotを持たない ] ⇒ ~RET ~false ◎ If x does not have a [[readableStreamController]] internal slot, return false.
- ~RET ~true ◎ Return true.
3.3.7. `IsReadableStreamDisturbed( stream )^A
この抽象~演算は、[ 可読~streamは一度でも読取されたか取消されたかどうか ]を照会したいと望むような,他の仕様から~callされる用途に意味されている。 ◎ This abstract operation is meant to be called from other specifications that may wish to query whether or not a readable stream has ever been read from or canceled.
- ~Assert: ! `IsReadableStream$A( %stream ) ~EQ ~true ◎ Assert: ! IsReadableStream(stream) is true.
- ~RET %stream.[[disturbed]] ◎ Return stream.[[disturbed]].
3.3.8. `IsReadableStreamLocked( stream )^A
この抽象~演算は、[ 可読~streamが読取器に`~lockされて$いるかどうか ]を照会したいと望むような,他の仕様から~callされる用途に意味されている。 ◎ This abstract operation is meant to be called from other specifications that may wish to query whether or not a readable stream is locked to a reader.
- ~Assert: ! `IsReadableStream$A( %stream ) ~EQ ~true ◎ Assert: ! IsReadableStream(stream) is true.
- ~IF[ %stream.[[reader]] ~EQ ~undefined ] ⇒ ~RET ~false ◎ If stream.[[reader]] is undefined, return false.
- ~RET ~true ◎ Return true.
3.3.9. `ReadableStreamTee( stream, cloneForBranch2 )^A
この抽象~演算は、所与の可読~streamを`二叉化-$したいと望むような,他の仕様から~callされる用途に意味されている。 ◎ This abstract operation is meant to be called from other specifications that may wish to tee a given readable stream.
2 個目の引数 %cloneForBranch2 は、元の~streamからの~dataが,[ 2 個目の分岐~内に現れる前に,~cloneされるかどうか(~HTMLによる,`直列化-可能$な~obj用の~frameworkを用いて) `HTML$r ]を統治する。 これは、両 分岐が消費されるとき — ~chunkを`転送する$ことにより— 互いに干渉しあうおそれがある局面で有用になる。 しかしながら、両 分岐の間に 外から見える非対称性も もたらされ,可能な`~chunk$も直列化-可能なものに制限されることになる。 ◎ The second argument, cloneForBranch2, governs whether or not the data from the original stream will be cloned (using HTML’s serializable objects framework) before appearing in the second of the returned branches. This is useful for scenarios where both branches are to be consumed in such a way that they might otherwise interfere with each other, such as by transferring their chunks. However, it does introduce a noticeable asymmetry between the two branches, and limits the possible chunks to serializable ones. [HTML]
注記: この標準においては、 `ReadableStreamTee$A が~callされるときは,常に %cloneForBranch2 は ~false に設定される。 他の仕様は ~true を渡す。 ◎ In this standard ReadableStreamTee is always called with cloneForBranch2 set to false; other specifications pass true.
- ~Assert: ! `IsReadableStream$A( %stream ) ~EQ ~true ◎ Assert: ! IsReadableStream(stream) is true.
- ~Assert: `Type$A( %cloneForBranch2 ) ~EQ `Boolean^b ◎ Assert: Type(cloneForBranch2) is Boolean.
- %reader ~LET ? `AcquireReadableStreamDefaultReader$A( %stream ) ◎ Let reader be ? AcquireReadableStreamDefaultReader(stream).
- %closedOrErrored ~LET ~false ◎ Let closedOrErrored be false.
- %canceled1 ~LET ~false ◎ Let canceled1 be false.
- %canceled2 ~LET ~false ◎ Let canceled2 be false.
- %reason1 ~LET ~undefined ◎ Let reason1 be undefined.
- %reason2 ~LET ~undefined ◎ Let reason2 be undefined.
- %branch1 ~LET ~undefined ◎ Let branch1 be undefined.
- %branch2 ~LET ~undefined ◎ Let branch2 be undefined.
- %cancelPromise ~LET `新たな~promise$ ◎ Let cancelPromise be a new promise.
-
%pullAlgorithm ~LET 次を走らす手続き: ◎ Let pullAlgorithm be the following steps:
-
~RET [ 引数 ( %result ) で~callされたとき,次の手続きを遂行する充足~handler ]で[ ! `ReadableStreamDefaultReaderRead$A( %reader ) ]の結果を`変形-$した結果: ◎ Return the result of transforming ! ReadableStreamDefaultReaderRead(reader) with a fulfillment handler which takes the argument result and performs the following steps:
- ~Assert: `Type$A( %result ) ~EQ `Object^b ◎ Assert: Type(result) is Object.
- %value ~LET ? `Get$A( %result, `value^l ) ◎ Let value be ? Get(result, "value").
- %done ~LET ? `Get$A( %result, `done^l ) ◎ Let done be ? Get(result, "done").
- ~Assert: `Type$A( %done ) ~EQ `Boolean^b ◎ Assert: Type(done) is Boolean.
-
~IF[ %done ~EQ ~true ]~AND[ %closedOrErrored ~EQ ~false ]: ◎ If done is true and closedOrErrored is false,
-
~IF[ %canceled1 ~EQ ~false ]: ◎ If canceled1 is false,
- ! `ReadableStreamDefaultControllerClose$A( %branch1.[[readableStreamController]] ) ◎ Perform ! ReadableStreamDefaultControllerClose(branch1.[[readableStreamController]]).
-
~IF[ %canceled2 ~EQ ~false ]: ◎ If canceled2 is false,
- ! `ReadableStreamDefaultControllerClose$A( %branch2.[[readableStreamController]] ) ◎ Perform ! ReadableStreamDefaultControllerClose(branch2.[[readableStreamController]]).
- %closedOrErrored ~SET ~true ◎ Set closedOrErrored to true.
-
- ~IF[ %closedOrErrored ~EQ ~true ] ⇒ ~RET ◎ If closedOrErrored is true, return.
- ( %value1, %value2 ) ~LET ( %value, %value ) ◎ Let value1 and value2 be value.
- ~IF[ %canceled2 ~EQ ~false ]~AND[ %cloneForBranch2 ~EQ ~true ] ⇒ %value2 ~SET ? `StructuredDeserialize$A( ? `StructuredSerialize$A( %value2 ), `現在の~Realm~Record$ ) ◎ If canceled2 is false and cloneForBranch2 is true, set value2 to ? StructuredDeserialize(? StructuredSerialize(value2), the current Realm Record).
- ~IF[ %canceled1 ~EQ ~false ] ⇒ ? `ReadableStreamDefaultControllerEnqueue$A( %branch1[[readableStreamController]], %value1 ) ◎ If canceled1 is false, perform ? ReadableStreamDefaultControllerEnqueue(branch1.[[readableStreamController]], value1).
- ~IF[ %canceled2 ~EQ ~false ] ⇒ ? `ReadableStreamDefaultControllerEnqueue$A( %branch2.[[readableStreamController]], %value2 ) ◎ If canceled2 is false, perform ? ReadableStreamDefaultControllerEnqueue(branch2.[[readableStreamController]], value2).
-
-
%cancel1Algorithm ~LET 引数 ( %reason ) をとり,次を走らす手続き: ◎ Let cancel1Algorithm be the following steps, taking a reason argument:
- %canceled1 ~SET ~true ◎ Set canceled1 to true.
- %reason1 ~SET %reason ◎ Set reason1 to reason.
-
~IF[ %canceled2 ~EQ ~true ]: ◎ If canceled2 is true,
- %compositeReason ~LET ! `CreateArrayFromList$A( « %reason1, %reason2 » ) ◎ Let compositeReason be ! CreateArrayFromList(« reason1, reason2 »).
- %cancelResult ~LET ! `ReadableStreamCancel$A( %stream, %compositeReason ) ◎ Let cancelResult be ! ReadableStreamCancel(stream, compositeReason).
- %cancelResult で %cancelPromise を`解決する$ ◎ Resolve cancelPromise with cancelResult.
- ~RET %cancelPromise ◎ Return cancelPromise.
-
%cancel2Algorithm ~LET 引数 ( %reason ) をとり,次を走らす手続き: ◎ Let cancel2Algorithm be the following steps, taking a reason argument:
- %canceled2 ~SET ~true ◎ Set canceled2 to true.
- %reason2 ~SET %reason ◎ Set reason2 to reason.
-
~IF[ %canceled1 ~EQ ~true ]: ◎ If canceled1 is true,
- %compositeReason ~LET ! `CreateArrayFromList$A( « %reason1, %reason2 » ) ◎ Let compositeReason be ! CreateArrayFromList(« reason1, reason2 »).
- %cancelResult ~LET ! `ReadableStreamCancel$A( %stream, %compositeReason ) ◎ Let cancelResult be ! ReadableStreamCancel(stream, compositeReason).
- %cancelResult で %cancelPromise を`解決する$ ◎ Resolve cancelPromise with cancelResult.
- ~RET %cancelPromise ◎ Return cancelPromise.
- %startAlgorithm ~LET ~undefined を返す~algo ◎ Let startAlgorithm be an algorithm that returns undefined.
- %branch1 ~SET ! `CreateReadableStream$A( %startAlgorithm, %pullAlgorithm, %cancel1Algorithm) ◎ Set branch1 to ! CreateReadableStream(startAlgorithm, pullAlgorithm, cancel1Algorithm).
- %branch2 ~SET ! `CreateReadableStream$A( %startAlgorithm, %pullAlgorithm, %cancel2Algorithm) ◎ Set branch2 to ! CreateReadableStream(startAlgorithm, pullAlgorithm, cancel2Algorithm).
-
事由 %r による %reader.[[closedPromise]] の`却下-時$には: ◎ Upon rejection of reader.[[closedPromise]] with reason r,
-
~IF[ %closedOrErrored ~EQ ~false ]: ◎ If closedOrErrored is false, then:
- ! `ReadableStreamDefaultControllerError$A( %branch1.[[readableStreamController]], %r ) ◎ Perform ! ReadableStreamDefaultControllerError(branch1.[[readableStreamController]], r).
- ! `ReadableStreamDefaultControllerError$A( %branch2.[[readableStreamController]], %r ) ◎ Perform ! ReadableStreamDefaultControllerError(branch2.[[readableStreamController]], r).
- %closedOrErrored ~SET ~true ◎ Set closedOrErrored to true.
-
- ~RET « %branch1, %branch1 » ◎ Return « branch1, branch2 ».
3.4. 可読~streamと制御器との間の~interface
仕様の~~構成においては、多様になり得る~logicを成す大部分を 2 種の制御器~class[ `ReadableStreamDefaultController$C, `ReadableByteStreamController$C ]の内側に集中させることにより、[ 単純な`可読~stream$, および`可読~byte~stream$ ]両者の挙動が,単独の `ReadableStream$C ~classの中に~encapsulateされている。 これらの制御器~classは、[ ~streamの`内部~queue$を管理する方法, および ~streamの[ `下層~源$/`下層~byte源$ ]とやりとりするための[ ~statefulな内部~slotを成す大部分, および抽象~演算 ]を定義する。 ◎ In terms of specification factoring, the way that the ReadableStream class encapsulates the behavior of both simple readable streams and readable byte streams into a single class is by centralizing most of the potentially-varying logic inside the two controller classes, ReadableStreamDefaultController and ReadableByteStreamController. Those classes define most of the stateful internal slots and abstract operations for how a stream’s internal queue is managed and how it interfaces with its underlying source or underlying byte source.
各~制御器~classは、 2 つの内部~methodを定義する — それらは、 `ReadableStream$C の各種~algoから~callされる: ◎ Each controller class defines two internal methods, which are called by the ReadableStream algorithms:
- `[[CancelSteps]]@( %reason )
- ~streamが`取消され$たときの反応として走らす,制御器の手続き。 制御器に格納されている状態を片付けて,`下層~源$に伝えるために利用される。 ◎ The controller’s steps that run in reaction to the stream being canceled, used to clean up the state stored in the controller and inform the underlying source.
- `[[PullSteps]]@()
- `既定の読取器$から読取されるときに走らす,制御器の手続き。 [ ~queue済みの`~chunk$を制御器から~pullする / もっと~chunkを取得するため`下層~源$から~pullする ]ために利用される。 ◎ The controller’s steps that run when a default reader is read from, used to pull from the controller any queued chunks, or pull from the underlying source to get more chunks.
(これらは、制御器の型に応じて分岐させることなく,各種 `ReadableStream$C ~algoから多形態的に~callできるよう、抽象~演算としてではなく,内部~methodとして定義される。) ◎ (These are defined as internal methods, instead of as abstract operations, so that they can be called polymorphically by the ReadableStream algorithms, without having to branch on which type of controller is present.)
この節の以降では、上述とは別方向の抽象~演算について注力する: それらは、制御器~実装により,それぞれに結付けられている `ReadableStream$C ~objに影響させるために利用される。 これらは、制御器における内部~状態~変化を, `ReadableStream$C の~public~APIを通して開発者に可視になる結果に翻訳する。 ◎ The rest of this section concerns abstract operations that go in the other direction: they are used by the controller implementations to affect their associated ReadableStream object. This translates internal state changes of the controller into developer-facing results visible through the ReadableStream's public API.
3.4.1. `ReadableStreamAddReadIntoRequest( stream, forAuthorCode )^A
- ~Assert: ! `IsReadableStreamBYOBReader$A( %stream.[[reader]] ) ~EQ ~true ◎ Assert: ! IsReadableStreamBYOBReader(stream.[[reader]]) is true.
- ~Assert: %stream.[[state]] ~IN { `readable^l, `closed^l } ◎ Assert: stream.[[state]] is "readable" or "closed".
- %promise ~LET `新たな~promise$ ◎ Let promise be a new promise.
- %readIntoRequest ~LET `~Record$ { [[promise]]: %promise, [[forAuthorCode]]: %forAuthorCode } ◎ Let readIntoRequest be Record {[[promise]]: promise, [[forAuthorCode]]: forAuthorCode}.
- %stream.[[reader]].[[readIntoRequests]] の~~末尾に %readIntoRequest を付加する ◎ Append readIntoRequest as the last element of stream.[[reader]].[[readIntoRequests]].
- ~RET %promise ◎ Return promise.
3.4.2. `ReadableStreamAddReadRequest( stream, forAuthorCode )^A
- ~Assert: ! `IsReadableStreamDefaultReader$A( %stream.[[reader]] ) ~EQ ~true ◎ Assert: ! IsReadableStreamDefaultReader(stream.[[reader]]) is true.
- ~Assert: %stream.[[state]] ~EQ `readable^l ◎ Assert: stream.[[state]] is "readable".
- %promise ~LET `新たな~promise$ ◎ Let promise be a new promise.
- %readRequest ~LET `~Record$ { [[promise]]: %promise, [[forAuthorCode]]: %forAuthorCode } ◎ Let readRequest be Record {[[promise]]: promise, [[forAuthorCode]]: forAuthorCode}.
- %stream.[[reader]].[[readRequests]] の~~末尾に %readRequest を付加する ◎ Append readRequest as the last element of stream.[[reader]].[[readRequests]].
- ~RET %promise ◎ Return promise.
3.4.3. `ReadableStreamCancel( stream, reason )^A
- %stream.[[disturbed]] ~SET ~true ◎ Set stream.[[disturbed]] to true.
- ~IF[ %stream.[[state]] ~EQ `closed^l ] ⇒ ~RET ~undefined で`解決される~promise$ ◎ If stream.[[state]] is "closed", return a promise resolved with undefined.
- ~IF[ %stream.[[state]] ~EQ `errored^l ] ⇒ ~RET %stream.[[storedError]] で`却下される~promise$ ◎ If stream.[[state]] is "errored", return a promise rejected with stream.[[storedError]].
- ! `ReadableStreamClose$A( %stream ) ◎ Perform ! ReadableStreamClose(stream).
- %sourceCancelPromise ~LET ! %stream.[[readableStreamController]].`[[CancelSteps]]$(%reason) ◎ Let sourceCancelPromise be ! stream.[[readableStreamController]].[[CancelSteps]](reason).
- ~RET [ ~undefined を返す充足~handler ]で %sourceCancelPromise を`変形-$した結果 ◎ Return the result of transforming sourceCancelPromise with a fulfillment handler that returns undefined.
3.4.4. `ReadableStreamClose( stream )^A
- ~Assert: %stream.[[state]] ~EQ `readable^l ◎ Assert: stream.[[state]] is "readable".
- %stream.[[state]] ~SET `closed^l ◎ Set stream.[[state]] to "closed".
- %reader ~LET %stream.[[%reader]] ◎ Let reader be stream.[[reader]].
- ~IF[ %reader ~EQ ~undefined ] ⇒ ~RET ◎ If reader is undefined, return.
-
~IF[ ! `IsReadableStreamDefaultReader$A( %reader ) ~EQ ~true ]: ◎ If ! IsReadableStreamDefaultReader(reader) is true,
-
%reader.[[readRequests]] 内の~EACH( %readRequest ) に対し: ◎ Repeat for each readRequest that is an element of reader.[[readRequests]],
- ! `ReadableStreamCreateReadResult$A( ~undefined, ~true, %readRequest.[[forAuthorCode]] ) で %readRequest.[[promise]] を`解決する$ ◎ Resolve readRequest.[[promise]] with ! ReadableStreamCreateReadResult(undefined, true, readRequest.[[forAuthorCode]]).
- %reader.[[readRequests]] ~SET 空`~List$ ◎ Set reader.[[readRequests]] to an empty List.
-
- ~undefined で %reader.[[closedPromise]] を`解決する$ ◎ Resolve reader.[[closedPromise]] with undefined.
[ %stream.[[state]] ~EQ `closed^l ]でありつつ[ %stream.[[closeRequested]] ~EQ ~false ]である事例は、~streamが,その制御器の `close()^m 関数が一度も~callされずに~closeされたとき — すなわち, ~streamが `cancel(reason)$rs の~callにより~closeされた場合 — に起こる。 この事例では、制御器の `close()^m ~methodが~callされても,何もせず黙することも許容される — 取消は下層~源の制御の外なので。 ◎ The case where stream.[[state]] is "closed", but stream.[[closeRequested]] is false, will happen if the stream was closed without its controller’s close method ever being called: i.e., if the stream was closed by a call to cancel(reason). In this case we allow the controller’s close method to be called and silently do nothing, since the cancelation was outside the control of the underlying source.
3.4.5. `ReadableStreamCreateReadResult( value , done , forAuthorCode )^A
この抽象~演算は、[ %forAuthorCode ~EQ ~true ]のときは, `CreateIterResultObject$A( %value, %done ) と同じ結果を与える。 これは、[ `defaultReader.read()^c / `byobReader.read()^c ]~methodから返される~objに対しては,期待される意味論を供する。 ◎ When forAuthorCode is true, this abstract operation gives the same result as CreateIterResultObject(value, done). This provides the expected semantics when the object is to be returned from the defaultReader.read() or byobReader.read() methods.
しかしながら,そのような~objで~promiseを解決するときには、 `Object.prototype.then^c への~accessが不可避になる。 内部~利用~用には — 特に `pipeTo()$rs や 他の仕様においては — 作者~codeが `Object.prototype^c を弄っていようが、読取は作者~codeからは観測-可能にならないことが重要になる。 この理由から, %forAuthorCode に対する ~false 値による結果は、~promise解決が観測-不能になるのを保つよう,~prototypeが `null^b にされた~objになる。 ◎ However, resolving promises with such objects will unavoidably result in an access to Object.prototype.then. For internal use, particularly in pipeTo() and in other specifications, it is important that reads not be observable by author code—even if that author code has tampered with Object.prototype. For this reason, a false value of forAuthorCode results in an object with a null prototype, keeping promise resolution unobservable.
ここで根底にある課題は、~streamからの読取りは,常に[ `{ value, done }^c ~obj用の~promise ]を — 仕様においても — 利用する点にある。 すべての内部~algoを,~promiseも~JS~objも利用しないように書き直して、代わりに, `read()^c ~methodが~callされたときの結果は[ `{ value, done }^c 用の~promise ]の中に梱包するに限ることも~~考えられるが、それは,未だ終えてない大仕事になる。 これについて,もっと背景を知りたければ、 whatwg/infra#181 を見よ。 ◎ The underlying issue here is that reading from streams always uses promises for { value, done } objects, even in specifications. Although it is conceivable we could rephrase all of the internal algorithms to not use promises and not use JavaScript objects, and instead only package up the results into promise-for-{ value, done } when a read() method is called, this would be a large undertaking, which we have not done. See whatwg/infra#181 for more background on this subject.
- %prototype ~LET `null^b ◎ Let prototype be null.
- ~IF[ %forAuthorCode ~EQ ~true ] ⇒ %prototype ~SET `~ObjectPrototype$ ◎ If forAuthorCode is true, set prototype to %ObjectPrototype%.
- ~Assert: `Type$Ax( %done ) ~EQ `Boolean^b ◎ Assert: Type(done) is Boolean.
- %obj ~LET `ObjectCreate$A( %prototype ) ◎ Let obj be ObjectCreate(prototype).
- `CreateDataProperty$A( %obj, `value^l, %value ) を遂行する ◎ Perform CreateDataProperty(obj, "value", value).
- `CreateDataProperty$A( %obj, `done^l, %done ) を遂行する ◎ Perform CreateDataProperty(obj, "done", done).
- ~RET %obj ◎ Return obj.
3.4.6. `ReadableStreamError( stream, e )^A
- ~Assert: ! `IsReadableStream$A( %stream ) ~EQ ~true ◎ Assert: ! IsReadableStream(stream) is true.
- ~Assert: %stream.[[state]] ~EQ `readable^l ◎ Assert: stream.[[state]] is "readable".
- %stream.[[state]] ~SET `errored^l ◎ Set stream.[[state]] to "errored".
- %stream.[[storedError]] ~SET %e ◎ Set stream.[[storedError]] to e.
- %reader ~LET %stream.[[%reader]] ◎ Let reader be stream.[[reader]].
- ~IF[ %reader ~EQ ~undefined ] ⇒ ~RET ◎ If reader is undefined, return.
-
~IF[ ! `IsReadableStreamDefaultReader$A( %reader ) ~EQ ~true ]: ◎ If ! IsReadableStreamDefaultReader(reader) is true,
-
%reader.[[readRequests]] 内の~EACH( %readRequest ) に対し: ◎ Repeat for each readRequest that is an element of reader.[[readRequests]],
- %e で %readRequest.[[promise]] を`却下する$ ◎ Reject readRequest.[[promise]] with e.
- %reader.[[readRequests]] ~SET 新たな空`~List$ ◎ Set reader.[[readRequests]] to a new empty List.
-
-
~ELSE: ◎ Otherwise,
- ~Assert: ! `IsReadableStreamBYOBReader$A( %reader ) ◎ Assert: ! IsReadableStreamBYOBReader(reader).
-
%reader.[[readIntoRequests]] 内の~EACH( %readIntoRequest ) に対し: ◎ Repeat for each readIntoRequest that is an element of reader.[[readIntoRequests]],
- %e で %readIntoRequest.[[promise]] を`却下する$ ◎ Reject readIntoRequest.[[promise]] with e.
- %reader.[[readIntoRequests]] ~SET 新たな空`~List$ ◎ Set reader.[[readIntoRequests]] to a new empty List.
- %e で %reader.[[closedPromise]] を`却下する$ ◎ Reject reader.[[closedPromise]] with e.
- %reader.[[closedPromise]].[[PromiseIsHandled]] ~SET ~true ◎ Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
3.4.7. `ReadableStreamFulfillReadIntoRequest( stream, chunk, done )^A
- %reader ~LET %stream.[[%reader]] ◎ Let reader be stream.[[reader]].
- %readIntoRequest ~LET %reader.[[readIntoRequests]] の最初の要素 ◎ Let readIntoRequest be the first element of reader.[[readIntoRequests]].
- %reader.[[readIntoRequests]] から %readIntoRequest を除去する — 後続の要素たちは~~先頭へ一つずらす ◎ Remove readIntoRequest from reader.[[readIntoRequests]], shifting all other elements downward (so that the second becomes the first, and so on).
- ! `ReadableStreamCreateReadResult$A( %chunk, %done, %readIntoRequest.[[forAuthorCode]] ) で %readIntoRequest.[[promise]] を`解決する$ ◎ Resolve readIntoRequest.[[promise]] with ! ReadableStreamCreateReadResult(chunk, done, readIntoRequest.[[forAuthorCode]]).
3.4.8. `ReadableStreamFulfillReadRequest( stream, chunk, done )^A
- %reader ~LET %stream.[[%reader]] ◎ Let reader be stream.[[reader]].
- %readRequest ~LET %reader.[[readRequests]] の最初の要素 ◎ Let readRequest be the first element of reader.[[readRequests]].
- %reader.[[readRequests]] から %readRequest を除去する — 後続の要素たちは~~先頭へ一つずらす ◎ Remove readRequest from reader.[[readRequests]], shifting all other elements downward (so that the second becomes the first, and so on).
- ! `ReadableStreamCreateReadResult$A( %chunk, %done, %readRequest.[[forAuthorCode]] ) で %readRequest.[[promise]] を`解決する$ ◎ Resolve readRequest.[[promise]] with ! ReadableStreamCreateReadResult(chunk, done, readRequest.[[forAuthorCode]]).
3.4.9. `ReadableStreamGetNumReadIntoRequests( stream )^A
- ~RET %stream.[[reader]].[[readIntoRequests]] 内の要素~数 ◎ Return the number of elements in stream.[[reader]].[[readIntoRequests]].
3.4.10. `ReadableStreamGetNumReadRequests( stream )^A
- ~RET %stream.[[reader]].[[readRequests]] 内の要素~数 ◎ Return the number of elements in stream.[[reader]].[[readRequests]].
3.4.11. `ReadableStreamHasBYOBReader( stream )^A
- %reader ~LET %stream.[[%reader]] ◎ Let reader be stream.[[reader]].
- ~IF[ %reader ~EQ ~undefined ] ⇒ ~RET ~false ◎ If reader is undefined, return false.
- ~IF[ ! `IsReadableStreamBYOBReader$A( %reader )~EQ ~false ] ⇒ ~RET ~false ◎ If ! IsReadableStreamBYOBReader(reader) is false, return false.
- ~RET ~true ◎ Return true.
3.4.12. `ReadableStreamHasDefaultReader( stream )^A
- %reader ~LET %stream.[[%reader]] ◎ Let reader be stream.[[reader]].
- ~IF[ %reader ~EQ ~undefined ] ⇒ ~RET ~false ◎ If reader is undefined, return false.
- ~IF[ ! `IsReadableStreamDefaultReader$A( %reader ) ~EQ ~false ] ⇒ ~RET ~false ◎ If ! IsReadableStreamDefaultReader(reader) is false, return false.
- ~RET ~true ◎ Return true.
3.5. `ReadableStreamDefaultReader^C ~class
`ReadableStreamDefaultReader$C ~classは、[ `ReadableStream$C ~instanceから配給されるように設計された `既定の読取器$ ]を表現する。 ◎ The ReadableStreamDefaultReader class represents a default reader designed to be vended by a ReadableStream instance.
3.5.1. ~class定義
~INFORMATIVE`ReadableStreamDefaultReader$C ~classは、 `ECMASCRIPT$r 風の構文で書くならば,次のようになる: ◎ If one were to write the ReadableStreamDefaultReader class in something close to the syntax of [ECMASCRIPT], it would look like
class ReadableStreamDefaultReader { `constructor(stream)$dr get `closed()$dr `cancel(reason)$dr `read()$dr `releaseLock()$dr }
3.5.2. 内部~slot
`ReadableStreamDefaultReader$C の各~instanceは、次の一覧に述べる各種 内部~slotを伴って作成される: ◎ Instances of ReadableStreamDefaultReader are created with the internal slots described in the following table:
内部~slot | 説明0(参考) |
---|---|
[[closedPromise]] | この読取器の `closed$dr 取得子から返される~promise。 ◎ A promise returned by the reader’s closed getter |
[[ownerReadableStream]] | この読取器を所有する `ReadableStream$C ~instance ◎ A ReadableStream instance that owns this reader |
[[readRequests]] | [[[ `消費器$が`~chunk$たちを可用になるより早く要請する ]ことに因り,まだ解決されていない ]ような,~promiseたち ]からなる`~List$ — 読取器の `read()$dr ~methodの~callから返される。 `IsReadableStreamDefaultReader$A による~brand検査-時にも利用される。 ◎ A List of promises returned by calls to the reader’s read() method that have not yet been resolved, due to the consumer requesting chunks sooner than they are available; also used for the IsReadableStreamDefaultReader brand check |
3.5.3. `new ReadableStreamDefaultReader(stream)^dr
`ReadableStreamDefaultReader()^dr 構築子は、一般に,直接的な利用は意味されていない — 代わりに,~streamの `getReader()$rs ~methodが利用されるべきである。 ◎ The ReadableStreamDefaultReader constructor is generally not meant to be used directly; instead, a stream’s getReader() method ought to be used.
- ~IF[ ! `IsReadableStream$A( %stream ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStream(stream) is false, throw a TypeError exception.
- ~IF[ ! `IsReadableStreamLocked$A( %stream ) ~EQ ~true ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStreamLocked(stream) is true, throw a TypeError exception.
- ! `ReadableStreamReaderGenericInitialize$A( ~this, %stream ) ◎ Perform ! ReadableStreamReaderGenericInitialize(this, stream).
- ~this.[[readRequests]] ~SET 新たな空`~List$ ◎ Set this.[[readRequests]] to a new empty List.
3.5.4. `ReadableStreamDefaultReader^C ~prototypeの各種~prop
3.5.4.1. `get closed^dr
`closed^dr 取得子は、~promiseを返す — それは、~streamが~closeされたときは 充足され,[ ~streamがどこかで~errorしたとき / ~streamが~closeし終える前に読取器の~lockが`解放-$されたとき ]は 却下されることになる。 ◎ The closed getter returns a promise that will be fulfilled when the stream becomes closed, or rejected if the stream ever errors or the reader’s lock is released before the stream finishes closing.
- ~IF[ ! `IsReadableStreamDefaultReader$A( ~this ) ~EQ ~false ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsReadableStreamDefaultReader(this) is false, return a promise rejected with a TypeError exception.
- ~RET ~this.[[closedPromise]] ◎ Return this.[[closedPromise]].
3.5.4.2. `cancel(reason)^dr
読取器の `cancel()^dr ~methodは、`作動中$のときは,結付けられている~stream用のそれと同じに挙動する。 ◎ If the reader is active, the cancel method behaves the same as that for the associated stream.
- ~IF[ ! `IsReadableStreamDefaultReader$A( ~this ) ~EQ ~false ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsReadableStreamDefaultReader(this) is false, return a promise rejected with a TypeError exception.
- ~IF[ ~this.[[ownerReadableStream]] ~EQ ~undefined ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If this.[[ownerReadableStream]] is undefined, return a promise rejected with a TypeError exception.
- ~RET ! `ReadableStreamReaderGenericCancel$A( ~this, %reason ) ◎ Return ! ReadableStreamReaderGenericCancel(this, reason).
3.5.4.3. `read()^dr
`read()^dr ~methodは、[ ~streamの内部~queueから,次回の可用な`~chunk$に~accessできる ]ようにする,~promiseを返す。 この~promiseは: ◎ The read method will return a promise that allows access to the next chunk from the stream’s internal queue, if available.
- 可用な~chunkが無くなったときは、 `{ value: theChunk, done: false }^c の形による~objで充足されることになる。 ◎ If the chunk does become available, the promise will be fulfilled with an object of the form { value: theChunk, done: false }.
- ~streamが~closeされたときは、 `{ value: undefined, done: true }^c の形による~objで充足されることになる。 ◎ If the stream becomes closed, the promise will be fulfilled with an object of the form { value: undefined, done: true }.
- ~streamが~errorしたときは、関連する~errorで却下されることになる。 ◎ If the stream becomes errored, the promise will be rejected with the relevant error.
~chunkの読取りにより~queueが空になったときは、`下層~源$から更なる~dataが~pullされることになる。 ◎ If reading a chunk causes the queue to become empty, more data will be pulled from the underlying source.
- ~IF[ ! `IsReadableStreamDefaultReader$A( ~this ) ~EQ ~false ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsReadableStreamDefaultReader(this) is false, return a promise rejected with a TypeError exception.
- ~IF[ ~this.[[ownerReadableStream]] ~EQ ~undefined ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If this.[[ownerReadableStream]] is undefined, return a promise rejected with a TypeError exception.
- ~RET ! `ReadableStreamDefaultReaderRead$A( ~this, ~true ) ◎ Return ! ReadableStreamDefaultReaderRead(this, true).
3.5.4.4. `releaseLock()^dr
`releaseLock()^dr ~methodは、対応する~stream上の読取器の`~lockを解放-$する。 解放されたなら、読取器は`作動中$でなくなる。 ~lockが解放された時点から、読取器は,[ 結付けられている~streamが~errorした場合は~errorしたように/ 他の場合は~closeされたように ]現れるようになる。 ◎ The releaseLock method releases the reader’s lock on the corresponding stream. After the lock is released, the reader is no longer active. If the associated stream is errored when the lock is released, the reader will appear errored in the same way from now on; otherwise, the reader will appear closed.
読取器の~lockは、処理待ちにある読取~要請が まだある間 — すなわち,読取器の `read()$dr ~methodから返された~promiseがまだ決着していない間 — は、解放できない。 そのような試みは、 `TypeError^b を投出させ,~streamは読取器に~lockされたままになる。 ◎ A reader’s lock cannot be released while it still has a pending read request, i.e., if a promise returned by the reader’s read() method has not yet been settled. Attempting to do so will throw a TypeError and leave the reader locked to the stream.
- ~IF[ ! `IsReadableStreamDefaultReader$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStreamDefaultReader(this) is false, throw a TypeError exception.
- ~IF[ ~this.[[ownerReadableStream]] ~EQ ~undefined ] ⇒ ~RET ◎ If this.[[ownerReadableStream]] is undefined, return.
- ~IF[ ~this.[[readRequests]] は空でない ] ⇒ ~THROW `TypeError^b ◎ If this.[[readRequests]] is not empty, throw a TypeError exception.
- ! `ReadableStreamReaderGenericRelease$A( ~this ) ◎ Perform ! ReadableStreamReaderGenericRelease(this).
3.6. `ReadableStreamBYOBReader^C ~class
`ReadableStreamBYOBReader$C ~classは、[ `ReadableStream$C ~instanceにより配給されるように設計された `~BYOB読取器$ ]を表現する。 ◎ The ReadableStreamBYOBReader class represents a BYOB reader designed to be vended by a ReadableStream instance.
3.6.1. ~class定義
~INFORMATIVE`ReadableStreamBYOBReader$C ~classは、 `ECMASCRIPT$r 風の構文で書くならば,次のようになる: ◎ If one were to write the ReadableStreamBYOBReader class in something close to the syntax of [ECMASCRIPT], it would look like
class ReadableStreamBYOBReader { `constructor(stream)$byob get `closed()$byob `cancel(reason)$byob `read(view)$byob `releaseLock()$byob }
3.6.2. 内部~slot
`ReadableStreamBYOBReader$C の各~instanceは、次の一覧に述べる各種 内部~slotを伴って作成される: ◎ Instances of ReadableStreamBYOBReader are created with the internal slots described in the following table:
内部~slot | 説明0(参考) |
---|---|
[[closedPromise]] | この読取器の `closed$byob 取得子から返される~promise。 ◎ A promise returned by the reader’s closed getter |
[[ownerReadableStream]] | この読取器を所有する `ReadableStream$C ~instance ◎ A ReadableStream instance that owns this reader |
[[readIntoRequests]] | [[[ `消費器$が`~chunk$たちを可用になるより早く要請する ]ことに因り,まだ解決されていない ]ような,~promiseたち ]からなる`~List$ — 読取器の `read(view)$byob ~methodの~callから返される。 `IsReadableStreamBYOBReader$A による~brand検査-時にも利用される。 ◎ A List of promises returned by calls to the reader’s read(view) method that have not yet been resolved, due to the consumer requesting chunks sooner than they are available; also used for the IsReadableStreamBYOBReader brand check |
3.6.3. `new ReadableStreamBYOBReader(stream)^byob
`ReadableStreamBYOBReader()^byob 構築子は、一般に,直接的な利用は意味されていない — 代わりに,~streamの `getReader()$rs ~methodが利用されるべきである。 ◎ The ReadableStreamBYOBReader constructor is generally not meant to be used directly; instead, a stream’s getReader() method ought to be used.
- ~IF[ ! `IsReadableStream$A( %stream ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStream(stream) is false, throw a TypeError exception.
- ~IF[ ! `IsReadableByteStreamController$A( %stream.[[readableStreamController]] ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableByteStreamController(stream.[[readableStreamController]]) is false, throw a TypeError exception.
- ~IF[ ! `IsReadableStreamLocked$A( %stream ) ~EQ ~true ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStreamLocked(stream) is true, throw a TypeError exception.
- ! `ReadableStreamReaderGenericInitialize$A( ~this, %stream ) ◎ Perform ! ReadableStreamReaderGenericInitialize(this, stream).
- ~this.[[readIntoRequests]] ~SET 新たな空`~List$ ◎ Set this.[[readIntoRequests]] to a new empty List.
3.6.4. `ReadableStreamBYOBReader^C ~prototypeの各種~prop
3.6.4.1. `get closed^byob
`closed^dr 取得子は、~promiseを返す — それは、~streamが~closeされたときは 充足され,[ ~streamがどこかで~errorしたとき / ~streamが~closeし終える前に読取器の~lockが`解放-$されたとき ]は 却下されることになる。 ◎ The closed getter returns a promise that will be fulfilled when the stream becomes closed, or rejected if the stream ever errors or the reader’s lock is released before the stream finishes closing.
- ~IF[ ! `IsReadableStreamBYOBReader$A( ~this ) ~EQ ~false ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsReadableStreamBYOBReader(this) is false, return a promise rejected with a TypeError exception.
- ~RET ~this.[[closedPromise]] ◎ Return this.[[closedPromise]].
3.6.4.2. `cancel(reason)^byob
`cancel()^dr ~methodは、読取器が`作動中$の間は,結付けられている~stream用の同名の~methodと同じに挙動する。 ◎ If the reader is active, the cancel method behaves the same as that for the associated stream.
- ~IF[ ! `IsReadableStreamBYOBReader$A( ~this ) ~EQ ~false ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsReadableStreamBYOBReader(this) is false, return a promise rejected with a TypeError exception.
- ~IF[ ~this.[[ownerReadableStream]] ~EQ ~undefined ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If this.[[ownerReadableStream]] is undefined, return a promise rejected with a TypeError exception.
- ~RET ! `ReadableStreamReaderGenericCancel$A( ~this, %reason ) ◎ Return ! ReadableStreamReaderGenericCancel(this, reason).
3.6.4.3. `read(view)^byob
`read()^byob ~methodは、~byte列を`view^m の中へ読取して,下に述べるような~bufferで解決されることになる~promiseを返す — この~bufferは、転送される場合もある。 ◎ The read method will write read bytes into view and return a promise resolved with a possibly transferred buffer as described below.
- 可用な~chunkが無くなったときは、 `{ value: theChunk, done: false }^c の形による~objで充足されることになる。 ◎ If the chunk does become available, the promise will be fulfilled with an object of the form { value: theChunk, done: false }.
- ~streamが~closeされたときは、 `{ value: undefined, done: true }^c の形による~objで充足されることになる。 ◎ If the stream becomes closed, the promise will be fulfilled with an object of the form { value: undefined, done: true }.
- ~streamが~errorしたときは、関連する~errorで却下されることになる。 ◎ If the stream becomes errored, the promise will be rejected with the relevant error.
~chunkの読取~時に~queueが空になった場合、`下層~byte源$から更なる~dataが~pullされる。 ◎ If reading a chunk causes the queue to become empty, more data will be pulled from the underlying byte source.
- ~IF[ ! `IsReadableStreamBYOBReader$A( ~this ) ~EQ ~false ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsReadableStreamBYOBReader(this) is false, return a promise rejected with a TypeError exception.
- ~IF[ ~this.[[ownerReadableStream]] ~EQ ~undefined ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If this.[[ownerReadableStream]] is undefined, return a promise rejected with a TypeError exception.
- ~IF[ `Type$A( %view ) ~NEQ `Object^b ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If Type(view) is not Object, return a promise rejected with a TypeError exception.
- ~IF[ %view は [[ViewedArrayBuffer]] 内部~slotを持たない ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If view does not have a [[ViewedArrayBuffer]] internal slot, return a promise rejected with a TypeError exception.
- ~IF[ ! `IsDetachedBuffer$A( %view.[[ViewedArrayBuffer]] ) ~EQ ~true ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsDetachedBuffer(view.[[ViewedArrayBuffer]]) is true, return a promise rejected with a TypeError exception.
- ~IF[ %view.[[ByteLength]] ~EQ `0^b ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If view.[[ByteLength]] is 0, return a promise rejected with a TypeError exception.
- ~RET ! `ReadableStreamBYOBReaderRead$A( ~this, %view, ~true ) ◎ Return ! ReadableStreamBYOBReaderRead(this, view, true).
3.6.4.4. `releaseLock()^byob
`releaseLock()^byob ~methodは、対応する~stream上の読取器の`~lockを解放-$する。 解放されたなら、読取器は`作動中$でなくなる。 ~lockが解放された時点から、読取器は,[ 結付けられている~streamが~errorした場合は~errorしたように/ 他の場合は~closeされたように ]現れるようになる。 ◎ The releaseLock method releases the reader’s lock on the corresponding stream. After the lock is released, the reader is no longer active. If the associated stream is errored when the lock is released, the reader will appear errored in the same way from now on; otherwise, the reader will appear closed.
読取器の~lockは、処理待ちにある読取~要請が まだある間 — すなわち,読取器の `read()$byob ~methodから返された~promiseがまだ決着していない間 — は、解放できない。 そのような試みは、 `TypeError^b を投出させ,~streamは読取器に~lockされたままになる。 ◎ A reader’s lock cannot be released while it still has a pending read request, i.e., if a promise returned by the reader’s read() method has not yet been settled. Attempting to do so will throw a TypeError and leave the reader locked to the stream.
- ~IF[ ! `IsReadableStreamBYOBReader$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStreamBYOBReader(this) is false, throw a TypeError exception.
- ~IF[ ~this.[[ownerReadableStream]] ~EQ ~undefined ] ⇒ ~RET ◎ If this.[[ownerReadableStream]] is undefined, return.
- ~IF[ ~this.[[readIntoRequests]] は空でない ] ⇒ ~THROW `TypeError^b ◎ If this.[[readIntoRequests]] is not empty, throw a TypeError exception.
- ! `ReadableStreamReaderGenericRelease$A( ~this ) ◎ Perform ! ReadableStreamReaderGenericRelease(this).
3.7. 可読~stream読取器~用の抽象~演算
3.7.1. `IsReadableStreamDefaultReader( x )^A
- ~IF[ `Type$A(%x) ~NEQ `Object^b ] ⇒ ~RET ~false ◎ If Type(x) is not Object, return false.
- ~IF[ %x は [[readRequests]] 内部~slotを持たない ] ⇒ ~RET ~false ◎ If x does not have a [[readRequests]] internal slot, return false.
- ~RET ~true ◎ Return true.
3.7.2. `IsReadableStreamBYOBReader( x )^A
- ~IF[ `Type$A(%x) ~NEQ `Object^b ] ⇒ ~RET ~false ◎ If Type(x) is not Object, return false.
- ~IF[ %x は [[readIntoRequests]] 内部~slotを持たない ] ⇒ ~RET ~false ◎ If x does not have a [[readIntoRequests]] internal slot, return false.
- ~RET ~true ◎ Return true.
3.7.3. `ReadableStreamReaderGenericCancel( reader, reason )^A
- %stream ~LET %reader.[[ownerReadableStream]] ◎ Let stream be reader.[[ownerReadableStream]].
- ~Assert: %stream ~NEQ ~undefined ◎ Assert: stream is not undefined.
- ~RET ! `ReadableStreamCancel$A( %stream, %reason ) ◎ Return ! ReadableStreamCancel(stream, reason).
3.7.4. `ReadableStreamReaderGenericInitialize( reader, stream )^A
- %reader.[[ownerReadableStream]] ~SET %stream ◎ Set reader.[[ownerReadableStream]] to stream.
- %stream.[[reader]] ~SET %reader ◎ Set stream.[[reader]] to reader.
-
~IF[ %stream.[[state]] ~EQ `readable^l ]: ◎ If stream.[[state]] is "readable",
- %reader.[[closedPromise]] ~SET `新たな~promise$ ◎ Set reader.[[closedPromise]] to a new promise.
-
~ELIF %stream.[[state]] ~EQ `closed^l : ◎ Otherwise, if stream.[[state]] is "closed",
- %reader.[[closedPromise]] ~SET ~undefined で`解決される~promise$ ◎ Set reader.[[closedPromise]] to a promise resolved with undefined.
-
~ELSE: ◎ Otherwise,
- ~Assert: %stream.[[state]] ~EQ `errored^l ◎ Assert: stream.[[state]] is "errored".
- %reader.[[closedPromise]] ~SET %stream.[[storedError]] で`却下される~promise$ ◎ Set reader.[[closedPromise]] to a promise rejected with stream.[[storedError]].
- %reader.[[closedPromise]].[[PromiseIsHandled]] ~SET ~true ◎ Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
3.7.5. `ReadableStreamReaderGenericRelease( reader )^A
- ~Assert: %reader.[[ownerReadableStream]] ~NEQ ~undefined ◎ Assert: reader.[[ownerReadableStream]] is not undefined.
- ~Assert: %reader.[[ownerReadableStream]].[[reader]] ~EQ %reader ◎ Assert: reader.[[ownerReadableStream]].[[reader]] is reader.
- ~IF[ %reader.[[ownerReadableStream]].[[state]] ~EQ `readable^l ] ⇒ `TypeError^b で %reader.[[closedPromise]] を`却下する$ ◎ If reader.[[ownerReadableStream]].[[state]] is "readable", reject reader.[[closedPromise]] with a TypeError exception.
- ~ELSE ⇒ %reader.[[closedPromise]] ~SET `TypeError^b で`却下される~promise$ ◎ Otherwise, set reader.[[closedPromise]] to a promise rejected with a TypeError exception.
- %reader.[[closedPromise]].[[PromiseIsHandled]] ~SET ~true ◎ Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
- %reader.[[ownerReadableStream]].[[reader]] ~SET ~undefined ◎ Set reader.[[ownerReadableStream]].[[reader]] to undefined.
- %reader.[[ownerReadableStream]] ~SET ~undefined ◎ Set reader.[[ownerReadableStream]] to undefined.
3.7.6. `ReadableStreamBYOBReaderRead( reader, view [, forAuthorCode ] )^A
- ~IF[ %forAuthorCode は渡されていない ] ⇒ %forAuthorCode ~SET ~false ◎ If forAuthorCode was not passed, set it to false.
- %stream ~LET %reader.[[ownerReadableStream]] ◎ Let stream be reader.[[ownerReadableStream]].
- ~Assert: %stream ~NEQ ~undefined ◎ Assert: stream is not undefined.
- %stream.[[disturbed]] ~SET ~true ◎ Set stream.[[disturbed]] to true.
- ~IF[ %stream.[[state]] ~EQ `errored^l ] ⇒ ~RET %stream.[[storedError]] で`却下される~promise$ ◎ If stream.[[state]] is "errored", return a promise rejected with stream.[[storedError]].
- ~RET ! `ReadableByteStreamControllerPullInto$A( %stream.[[readableStreamController]], %view, %forAuthorCode ) ◎ Return ! ReadableByteStreamControllerPullInto(stream.[[readableStreamController]], view, forAuthorCode).
3.7.7. `ReadableStreamDefaultReaderRead( reader [, forAuthorCode ] )^A
注記: 他の仕様は、 %forAuthorCode を 既定の値 ~false のままにしておくものとする — 結果の `{ value, done }^c ~objを,作者に直に公開することを計画していない限り。 さらなる情報は、 ReadableStreamCreateReadResult に関する注記 を見よ。 ◎ Other specifications ought to leave forAuthorCode as its default value of false, unless they are planning to directly expose the resulting { value, done } object to authors. See the note regarding ReadableStreamCreateReadResult for more information.
- ~IF[ %forAuthorCode は渡されていない ] ⇒ %forAuthorCode ~SET ~false ◎ If forAuthorCode was not passed, set it to false.
- %stream ~LET %reader.[[ownerReadableStream]] ◎ Let stream be reader.[[ownerReadableStream]].
- ~Assert: %stream ~NEQ ~undefined ◎ Assert: stream is not undefined.
- %stream.[[disturbed]] ~SET ~true ◎ Set stream.[[disturbed]] to true.
- ~IF[ %stream.[[state]] ~EQ `closed^l ] ⇒ ~RET ! `ReadableStreamCreateReadResult$A( ~undefined, ~true, %forAuthorCode ) で`解決される~promise$ ◎ If stream.[[state]] is "closed", return a promise resolved with ! ReadableStreamCreateReadResult(undefined, true, forAuthorCode).
- ~IF[ %stream.[[state]] ~EQ `errored^l ] ⇒ ~RET %stream.[[storedError]] で`却下される~promise$ ◎ If stream.[[state]] is "errored", return a promise rejected with stream.[[storedError]].
- ~Assert: %stream.[[state]] ~EQ `readable^l ◎ Assert: stream.[[state]] is "readable".
- ~RET ! %stream.[[readableStreamController]].`[[PullSteps]]$( %forAuthorCode ) ◎ Return ! stream.[[readableStreamController]].[[PullSteps]](forAuthorCode).
3.8. `ReadableStreamDefaultController^C ~class
`ReadableStreamDefaultController$C ~classは、 `ReadableStream$C の状態と`内部~queue$を制御できるようにする~methodを持つ。 `可読~byte~stream$でない `ReadableStream$C を構築するときは、`下層~源$には,操作するための 対応する `ReadableStreamDefaultController$C ~instanceが与えられる。 ◎ The ReadableStreamDefaultController class has methods that allow control of a ReadableStream's state and internal queue. When constructing a ReadableStream that is not a readable byte stream, the underlying source is given a corresponding ReadableStreamDefaultController instance to manipulate.
3.8.1. ~class定義
~INFORMATIVE`ReadableStreamDefaultController$C ~classは、 `ECMASCRIPT$r 風の構文で書くならば,次のようになる: ◎ If one were to write the ReadableStreamDefaultController class in something close to the syntax of [ECMASCRIPT], it would look like
class ReadableStreamDefaultController {
`constructor()$rsdc /*
常に投出する
◎
always throws
*/
get `desiredSize()$rsdc
`close()$rsdc
`enqueue(chunk)$rsdc
`error(e)$rsdc
}
3.8.2. 内部~slot
`ReadableStreamDefaultController$C の各~instanceは、次の一覧に述べる各種 内部~slotを伴って作成される: ◎ Instances of ReadableStreamDefaultController are created with the internal slots described in the following table:
内部~slot | 説明0(参考) |
---|---|
[[cancelAlgorithm]] | 1 個の引数(取消-事由)をとり,~promiseを返す~algo — それは、要請された取消を`下層~源$に通信する。 ◎ A promise-returning algorithm, taking one argument (the cancel reason), which communicates a requested cancelation to the underlying source |
[[closeRequested]] | 真偽~flag — [ ~streamは`下層~源$により~closeされたが,その内部~queueには 読取されていない`~chunk$がまだある ]かどうかを指示する。 ◎ A boolean flag indicating whether the stream has been closed by its underlying source, but still has chunks in its internal queue that have not yet been read |
[[controlledReadableStream]] | 制御先の `ReadableStream$C の~instance。 ◎ The ReadableStream instance controlled |
[[pullAgain]] | 真偽~flag — 更に~dataを~pullするために,~streamの仕組みにて`下層~源$の~pull~algoが要請されたが、以前の~callがまだ実行-中にあるため,まだ~pullを行えない間は ~true に設定される。 ◎ A boolean flag set to true if the stream’s mechanisms requested a call to the underlying source’s pull algorithm to pull more data, but the pull could not yet be done since a previous call is still executing |
[[pullAlgorithm]] | ~promiseを返す~algo — それは、`下層~源$から~dataを~pullする。 ◎ A promise-returning algorithm that pulls data from the underlying source |
[[pulling]] | 真偽~flag — `下層~源$の~pull~algoは実行-中にあるが,それが返した~promiseはまだ充足されていない間は ~true に設定される。 これは、再入~callを防止するために利用される。 ◎ A boolean flag set to true while the underlying source’s pull algorithm is executing and the returned promise has not yet fulfilled, used to prevent reentrant calls |
[[queue]] | ~streamの[ `~chunk$たちからなる内部~queue ]を表現する`~List$ 。 ◎ A List representing the stream’s internal queue of chunks |
[[queueTotalSize]] | [[queue]] 内に格納されている すべての~chunkの合計~size(`§個別~size付き~queue演算$を見よ) ◎ The total size of all the chunks stored in [[queue]] (see §6.2 Queue-with-sizes operations) |
[[started]] | 真偽~flag — [ `下層~源$が開始処理を完遂した ]かどうかを指示する。 ◎ A boolean flag indicating whether the underlying source has finished starting |
[[strategyHWM]] | ~streamの`~queuing策$の一部として,構築子に給された~number — それを境に,~streamが`下層~源$に`背圧$を適用することになるような。 【 HWM = `High-Water Mark^en (限界水位) 】 ◎ A number supplied to the constructor as part of the stream’s queuing strategy, indicating the point at which the stream will apply backpressure to its underlying source |
[[strategySizeAlgorithm]] | ~streamの`~queuing策$の一部として,~enqueueされた`~chunk$たちの~sizeを計算する~algo。 ◎ An algorithm to calculate the size of enqueued chunks, as part of the stream’s queuing strategy |
3.8.3. `new ReadableStreamDefaultController()^rsdc
`ReadableStreamDefaultController()^rsdc 構築子は、直には利用できない — `ReadableStreamDefaultController$C ~instanceは、 `ReadableStream$C を構築する間に自動的に作成される。 ◎ The ReadableStreamDefaultController constructor cannot be used directly; ReadableStreamDefaultController instances are created automatically during ReadableStream construction.
- ~THROW `TypeError^b ◎ Throw a TypeError.
3.8.4. `ReadableStreamDefaultController^C ~prototypeの各種~prop
3.8.4.1. `get desiredSize^rsdc
`desiredSize^rsdc 取得子は、制御先の`~streamの内部~queueの残り~size$を返す。 それは、負にもなり得る — ~queueを溢れたときに。 `下層~源$が`背圧$をいつどのように適用するかを決定するときは、この情報が利用されるべきである。 ◎ The desiredSize getter returns the desired size to fill the controlled stream’s internal queue. It can be negative, if the queue is over-full. An underlying source ought to use this information to determine when and how to apply backpressure.
- ~IF[ ! `IsReadableStreamDefaultController$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStreamDefaultController(this) is false, throw a TypeError exception.
- ~RET ! `ReadableStreamDefaultControllerGetDesiredSize$A( ~this ) ◎ Return ! ReadableStreamDefaultControllerGetDesiredSize(this).
3.8.4.2. `close()^rsdc
`close()^rsdc ~methodは、制御先の可読~streamを~closeする。 `消費器$は依然として,それまでに~enqueueされた`~chunk$たちを~streamから読取できるが、それらが読取されたなら,~streamは~closeされる。 ◎ The close method will close the controlled readable stream. Consumers will still be able to read any previously-enqueued chunks from the stream, but once those are read, the stream will become closed.
- ~IF[ ! `IsReadableStreamDefaultController$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStreamDefaultController(this) is false, throw a TypeError exception.
- ~IF[ ! `ReadableStreamDefaultControllerCanCloseOrEnqueue$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(this) is false, throw a TypeError exception.
- ! `ReadableStreamDefaultControllerClose$A( ~this ) ◎ Perform ! ReadableStreamDefaultControllerClose(this).
3.8.4.3. `enqueue(chunk)^rsdc
`enqueue()^rsdc ~methodは、所与の`~chunk$を制御先の可読~stream内に~enqueueする。 ◎ The enqueue method will enqueue a given chunk in the controlled readable stream.
- ~IF[ ! `IsReadableStreamDefaultController$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStreamDefaultController(this) is false, throw a TypeError exception.
- ~IF[ ! `ReadableStreamDefaultControllerCanCloseOrEnqueue$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(this) is false, throw a TypeError exception.
- ~RET ? `ReadableStreamDefaultControllerEnqueue$A( ~this, %chunk ) ◎ Return ? ReadableStreamDefaultControllerEnqueue(this, chunk).
3.8.4.4. `error(e)^rsdc
`error()^rsdc ~methodは、可読~streamを~errorにする — 以降の相互作用は、すべて所与の~error %e で失敗させる。 ◎ The error method will error the readable stream, making all future interactions with it fail with the given error e.
- ~IF[ ! `IsReadableStreamDefaultController$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStreamDefaultController(this) is false, throw a TypeError exception.
- ! `ReadableStreamDefaultControllerError$A( ~this, %e ) ◎ Perform ! ReadableStreamDefaultControllerError(this, e).
3.8.5. 可読 ~streamの既定の制御器の各種 内部~method
以下のものは、各 `ReadableStreamDefaultController$C ~instanceにより実装される,追加の内部~methodである。 可読~streamの実装は、[ それら, または ~BYOB制御器~用の それらに相当するもの ]いずれかを多形態的に~callすることになる。 ◎ The following are additional internal methods implemented by each ReadableStreamDefaultController instance. The readable stream implementation will polymorphically call to either these or their counterparts for BYOB controllers.
3.8.5.1. `[[CancelSteps]]$( %reason )
- ! `ResetQueue$A( ~this ) ◎ Perform ! ResetQueue(this).
- ~RET 次を遂行した結果 ⇒ ~this.[[cancelAlgorithm]]( %reason ) ◎ Return the result of performing this.[[cancelAlgorithm]], passing reason.
3.8.5.2. `[[PullSteps]]$( %forAuthorCode )
- %stream ~LET ~this.[[controlledReadableStream]] ◎ Let stream be this.[[controlledReadableStream]].
-
~IF[ ~this.[[queue]] は空でない ]: ◎ If this.[[queue]] is not empty,
- %chunk ~LET ! `DequeueValue$A( ~this ) ◎ Let chunk be ! DequeueValue(this).
- ~IF[ ~this.[[closeRequested]] ~EQ ~true ]~AND[ ~this.[[queue]] は空である ] ⇒ ! `ReadableStreamClose$A( %stream ) ◎ If this.[[closeRequested]] is true and this.[[queue]] is empty, perform ! ReadableStreamClose(stream).
- ~ELSE ⇒ ! `ReadableStreamDefaultControllerCallPullIfNeeded$A( ~this ) ◎ Otherwise, perform ! ReadableStreamDefaultControllerCallPullIfNeeded(this).
- ~RET ! `ReadableStreamCreateReadResult$A( %chunk, ~false, %forAuthorCode ) で`解決される~promise$ ◎ Return a promise resolved with ! ReadableStreamCreateReadResult(chunk, false, forAuthorCode).
- %pendingPromise ~LET ! `ReadableStreamAddReadRequest$A( %stream, %forAuthorCode ) ◎ Let pendingPromise be ! ReadableStreamAddReadRequest(stream, forAuthorCode).
- ! `ReadableStreamDefaultControllerCallPullIfNeeded$A( ~this ) ◎ Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(this).
- ~RET %pendingPromise ◎ Return pendingPromise.
3.9. 可読 ~stream既定の制御器~用の抽象~演算
3.9.1. `IsReadableStreamDefaultController( x )^A
- ~IF[ `Type$A(%x) ~NEQ `Object^b ] ⇒ ~RET ~false ◎ If Type(x) is not Object, return false.
- ~IF[ %x は [[controlledReadableStream]] 内部~slotを持たない ] ⇒ ~RET ~false ◎ If x does not have a [[controlledReadableStream]] internal slot, return false.
- ~RET ~true ◎ Return true.
3.9.2. `ReadableStreamDefaultControllerCallPullIfNeeded( controller )^A
- %shouldPull ~LET ! `ReadableStreamDefaultControllerShouldCallPull$A( %controller ) ◎ Let shouldPull be ! ReadableStreamDefaultControllerShouldCallPull(controller).
- ~IF[ %shouldPull ~EQ ~false ] ⇒ ~RET ◎ If shouldPull is false, return.
-
~IF[ %controller.[[pulling]] ~EQ ~true ]: ◎ If controller.[[pulling]] is true,
- %controller.[[pullAgain]] ~SET ~true ◎ Set controller.[[pullAgain]] to true.
- ~RET ◎ Return.
- ~Assert: %controller .[[pullAgain]] ~EQ ~false ◎ Assert: controller.[[pullAgain]] is false.
- %controller.[[pulling]] ~SET ~true ◎ Set controller.[[pulling]] to true.
-
%pullPromise ~LET 次を遂行した結果 ⇒ %controller.[[pullAlgorithm]]() ◎ Let pullPromise be the result of performing controller.[[pullAlgorithm]].
-
%pullPromise の`充足-時$には: ◎ Upon fulfillment of pullPromise,
- %controller.[[pulling]] ~SET ~false ◎ Set controller.[[pulling]] to false.
-
~IF[ %controller.[[pullAgain]] ~EQ ~true ]: ◎ If controller.[[pullAgain]] is true,
- %controller.[[pullAgain]] ~SET ~false ◎ Set controller.[[pullAgain]] to false.
- ! `ReadableStreamDefaultControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(controller).
-
事由 %e による %pullPromise の`却下-時$には: ◎ Upon rejection of pullPromise with reason e,
- ! `ReadableStreamDefaultControllerError$A( %controller, %e ) ◎ Perform ! ReadableStreamDefaultControllerError(controller, e).
-
3.9.3. `ReadableStreamDefaultControllerShouldCallPull( controller )^A
- %stream ~LET %controller.[[controlledReadableStream]] ◎ Let stream be controller.[[controlledReadableStream]].
- ~IF[ ! `ReadableStreamDefaultControllerCanCloseOrEnqueue$A( %controller ) ~EQ ~false ] ⇒ ~RET ~false ◎ If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) is false, return false.
- ~IF[ %controller.[[started]] ~EQ ~false ] ⇒ ~RET ~false ◎ If controller.[[started]] is false, return false.
- ~IF[ ! `IsReadableStreamLocked$A( %stream ) ~EQ ~true ]~AND[ ! `ReadableStreamGetNumReadRequests$A( %stream ) ~GT `0^b ] ⇒ ~RET ~true ◎ If ! IsReadableStreamLocked(stream) is true and ! ReadableStreamGetNumReadRequests(stream) > 0, return true.
- %desiredSize ~LET ! `ReadableStreamDefaultControllerGetDesiredSize$A( %controller ) ◎ Let desiredSize be ! ReadableStreamDefaultControllerGetDesiredSize(controller).
- ~Assert: %desiredSize ~NEQ `null^b ◎ Assert: desiredSize is not null.
- ~IF[ %desiredSize ~GT `0^b ] ⇒ ~RET ~true ◎ If desiredSize > 0, return true.
- ~RET ~false ◎ Return false.
3.9.4. `ReadableStreamDefaultControllerClose( controller )^A
他の仕様は、可読~streamを~closeしたいと望むなら,この抽象~演算を~callできる — 開発者が作成した~streamが[ それに結付けられた制御器~objにより~closeされる ]のと同じ仕方で。 仕様は、自身が作成しなかった~streamに対し,これを行うべきでない — 事前条件(以下に~Assertとして挙げられる)が順守されることを確保し~MUST。 ◎ This abstract operation can be called by other specifications that wish to close a readable stream, in the same way a developer-created stream would be closed by its associated controller object. Specifications should not do this to streams they did not create, and must ensure they have obeyed the preconditions (listed here as asserts).
- %stream ~LET %controller.[[controlledReadableStream]] ◎ Let stream be controller.[[controlledReadableStream]].
- ~Assert: ! `ReadableStreamDefaultControllerCanCloseOrEnqueue$A( %controller ) ~EQ ~true ◎ Assert: ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) is true.
- %controller.[[closeRequested]] ~SET ~true ◎ Set controller.[[closeRequested]] to true.
- ~IF[ %controller.[[queue]] は空である ] ⇒ ! `ReadableStreamClose$A( %stream ) ◎ If controller.[[queue]] is empty, perform ! ReadableStreamClose(stream).
3.9.5. `ReadableStreamDefaultControllerEnqueue( controller, chunk )^A
他の仕様は、可読~stream内に`~chunk$たちを~enqueueしたいと望むなら,この抽象~演算を~callできる — 開発者が[ ~streamに結付けられた制御器~objを利用して,~chunkたちを~enqueueする ]のと同じ仕方で。 仕様は、自身が作成しなかった~streamに対し,これを行うべきでない — 事前条件(以下に~Assertとして挙げられる)が順守されることを確保し~MUST。 ◎ This abstract operation can be called by other specifications that wish to enqueue chunks in a readable stream, in the same way a developer would enqueue chunks using the stream’s associated controller object. Specifications should not do this to streams they did not create, and must ensure they have obeyed the preconditions (listed here as asserts).
- %stream ~LET %controller.[[controlledReadableStream]] ◎ Let stream be controller.[[controlledReadableStream]].
- ~Assert: ! `ReadableStreamDefaultControllerCanCloseOrEnqueue$A( %controller ) ~EQ ~true ◎ Assert: ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) is true.
- ~IF[ ! `IsReadableStreamLocked$A( %stream ) ~EQ ~true ]~AND[ ! `ReadableStreamGetNumReadRequests$A( %stream ) ~GT `0^b ] ⇒ ! `ReadableStreamFulfillReadRequest$A( %stream, %chunk, ~false ) ◎ If ! IsReadableStreamLocked(stream) is true and ! ReadableStreamGetNumReadRequests(stream) > 0, perform ! ReadableStreamFulfillReadRequest(stream, chunk, false).
-
~ELSE: ◎ Otherwise,
- %result ~LET 次を遂行した結果を~ECMAScript完了~値に解釈した結果 ⇒ %controller.[[strategySizeAlgorithm]]( %chunk ) ◎ Let result be the result of performing controller.[[strategySizeAlgorithm]], passing in chunk, and interpreting the result as an ECMAScript completion value.
-
~IF[ %result は`中途完了$である ]: ◎ If result is an abrupt completion,
- ! `ReadableStreamDefaultControllerError$A( %controller, %result.[[Value]] ) ◎ Perform ! ReadableStreamDefaultControllerError(controller, result.[[Value]]).
- ~RET %result ◎ Return result.
- %chunkSize ~LET %result.[[Value]] ◎ Let chunkSize be result.[[Value]].
- %enqueueResult ~LET `EnqueueValueWithSize$A( %controller, %chunk, %chunkSize ) ◎ Let enqueueResult be EnqueueValueWithSize(controller, chunk, chunkSize).
-
~IF[ %enqueueResult は`中途完了$である ]: ◎ If enqueueResult is an abrupt completion,
- ! `ReadableStreamDefaultControllerError$A( %controller, %enqueueResult.[[Value]] ) ◎ Perform ! ReadableStreamDefaultControllerError(controller, enqueueResult.[[Value]]).
- ~RET %enqueueResult ◎ Return enqueueResult.
- ! `ReadableStreamDefaultControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(controller).
3.9.6. `ReadableStreamDefaultControllerError( controller, e )^A
他の仕様は、可読~streamを~error状態へ移行させたいと望むなら,この抽象~演算を~callできる — 開発者が[ ~streamに結付けられた制御器~objを利用して,~streamを~errorにする ]のと同じ仕方で。 仕様は、自身が作成しなかった~streamに対し,これを行うべきでない。 ◎ This abstract operation can be called by other specifications that wish to move a readable stream to an errored state, in the same way a developer would error a stream using its associated controller object. Specifications should not do this to streams they did not create.
- %stream ~LET %controller.[[controlledReadableStream]] ◎ Let stream be controller.[[controlledReadableStream]].
- ~IF[ %stream.[[state]] ~NEQ `readable^l ] ⇒ ~RET ◎ If stream.[[state]] is not "readable", return.
- ! `ResetQueue$A( %controller ) ◎ Perform ! ResetQueue(controller).
- ! `ReadableStreamError$A( %stream, %e ) ◎ Perform ! ReadableStreamError(stream, e).
3.9.7. `ReadableStreamDefaultControllerGetDesiredSize( controller )^A
他の仕様は、この`~streamの内部~queueの残り~size$を決定したいと望むなら,この抽象~演算を~callできる — 開発者が[ ~streamに結付けられている制御器~objの `desiredSize^rsdc ~prop ]にあたるときと同様に。 仕様は、自身が作成していない~streamに対しては,これを利用するべきでない。 ◎ This abstract operation can be called by other specifications that wish to determine the desired size to fill this stream’s internal queue, similar to how a developer would consult the desiredSize property of the stream’s associated controller object. Specifications should not use this on streams they did not create.
- %stream ~LET %controller.[[controlledReadableStream]] ◎ Let stream be controller.[[controlledReadableStream]].
- %state ~LET %stream.[[state]] ◎ Let state be stream.[[state]].
- ~IF[ %state ~EQ `errored^l ] ⇒ ~RET `null^b ◎ If state is "errored", return null.
- ~IF[ %state ~EQ `closed^l ] ⇒ ~RET `0^b ◎ If state is "closed", return 0.
- ~RET %controller.[[strategyHWM]] − %controller.[[queueTotalSize]] ◎ Return controller.[[strategyHWM]] − controller.[[queueTotalSize]].
3.9.8. `ReadableStreamDefaultControllerHasBackpressure( controller )^A
注記: この抽象~演算は、 `TransformStream^C の実装に利用される。 ◎ This abstract operation is used in the implementation of TransformStream.
- ~IF[ ! `ReadableStreamDefaultControllerShouldCallPull$A( %controller ) ~EQ ~true ] ⇒ ~RET ~false ◎ If ! ReadableStreamDefaultControllerShouldCallPull(controller) is true, return false.
- ~RET ~true ◎ Otherwise, return true.
3.9.9. `ReadableStreamDefaultControllerCanCloseOrEnqueue( controller )^A
- %state ~LET %controller.[[controlledReadableStream]].[[state]] ◎ Let state be controller.[[controlledReadableStream]].[[state]].
- ~IF[ %controller.[[closeRequested]] ~EQ ~false ]~AND[ %state ~EQ `readable^l ] ⇒ ~RET ~true ◎ If controller.[[closeRequested]] is false and state is "readable", return true.
- ~RET ~false ◎ Otherwise, return false.
[ %stream.[[closeRequested]] ~EQ ~false ]でありつつ[ %stream.[[state]] ~NEQ `readable^l ]である事例は、次のときに起こる ⇒ ~streamが `error(e)$rsdc を介して~errorにされたとき / ~streamが,その制御器の `close()^rsdc 関数が一度も~callされずに ~closeされたとき — 例: `cancel(reason)$rs の~callにより,~streamは~closeされたとき ◎ The case where stream.[[closeRequested]] is false, but stream.[[state]] is not "readable", happens when the stream is errored via error(e), or when it is closed without its controller’s close method ever being called: e.g., if the stream was closed by a call to cancel(reason).
3.9.10. `SetUpReadableStreamDefaultController( stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm )^A
- ~Assert: %stream.[[readableStreamController]] ~EQ ~undefined ◎ Assert: stream.[[readableStreamController]] is undefined.
- %controller の ⇒# .[[controlledReadableStream]] ~SET %stream, .[[queue]] ~SET ~undefined, .[[queueTotalSize]] ~SET ~undefined ◎ Set controller.[[controlledReadableStream]] to stream. ◎ Set controller.[[queue]] and controller.[[queueTotalSize]] to undefined, then\
- ! `ResetQueue$A( %controller ) ◎ perform ! ResetQueue(controller).
- %controller の ⇒# .[[started]] ~SET ~false, .[[closeRequested]] ~SET ~false, .[[pullAgain]] ~SET ~false, .[[pulling]] ~SET ~false, .[[strategySizeAlgorithm]] ~SET %sizeAlgorithm, .[[strategyHWM]] ~SET %highWaterMark, .[[pullAlgorithm]] ~SET %pullAlgorithm, .[[cancelAlgorithm]] ~SET %cancelAlgorithm ◎ Set controller.[[started]], controller.[[closeRequested]], controller.[[pullAgain]], and controller.[[pulling]] to false. ◎ Set controller.[[strategySizeAlgorithm]] to sizeAlgorithm and controller.[[strategyHWM]] to highWaterMark. ◎ Set controller.[[pullAlgorithm]] to pullAlgorithm. ◎ Set controller.[[cancelAlgorithm]] to cancelAlgorithm.
- %stream.[[readableStreamController]] ~SET %controller ◎ Set stream.[[readableStreamController]] to controller.
- %startResult ~LET 次を遂行した結果(例外を投出し得る) ⇒ %startAlgorithm() ◎ Let startResult be the result of performing startAlgorithm. (This may throw an exception.)
-
%startPromise ~LET %startResult で`解決される~promise$ ◎ Let startPromise be a promise resolved with startResult.
-
%startPromise の`充足-時$には: ◎ Upon fulfillment of startPromise,
- %controller.[[started]] ~SET ~true ◎ Set controller.[[started]] to true.
- ~Assert: %controller.[[pulling]] ~EQ ~false ◎ Assert: controller.[[pulling]] is false.
- ~Assert: %controller.[[pullAgain]] ~EQ ~false ◎ Assert: controller.[[pullAgain]] is false.
- ! `ReadableStreamDefaultControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(controller).
-
事由 %r による %startPromise の`却下-時$には: ◎ Upon rejection of startPromise with reason r,
- ! `ReadableStreamDefaultControllerError$A( %controller, %r ) ◎ Perform ! ReadableStreamDefaultControllerError(controller, r).
-
3.9.11. `SetUpReadableStreamDefaultControllerFromUnderlyingSource( stream, underlyingSource, highWaterMark, sizeAlgorithm )^A
- ~Assert: %underlyingSource ~NEQ ~undefined ◎ Assert: underlyingSource is not undefined.
- %controller ~LET `ObjectCreate$A( `ReadableStreamDefaultController$C の `prototype^c ~propの元の値 ) ◎ Let controller be ObjectCreate(the original value of ReadableStreamDefaultController's prototype property).
-
%startAlgorithm ~LET 次を走らす手続き: ◎ Let startAlgorithm be the following steps:
- ~RET ? `InvokeOrNoop$A( %underlyingSource, `start^l, « %controller » ) ◎ Return ? InvokeOrNoop(underlyingSource, "start", « controller »).
- %pullAlgorithm ~LET ? `CreateAlgorithmFromUnderlyingMethod$A( %underlyingSource, `pull^l, `0^b, « %controller » ) ◎ Let pullAlgorithm be ? CreateAlgorithmFromUnderlyingMethod(underlyingSource, "pull", 0, « controller »).
- %cancelAlgorithm ~LET ? `CreateAlgorithmFromUnderlyingMethod$A( %underlyingSource, `cancel^l, `1^b, « » ) ◎ Let cancelAlgorithm be ? CreateAlgorithmFromUnderlyingMethod(underlyingSource, "cancel", 1, « »).
- ? `SetUpReadableStreamDefaultController$A( %stream, %controller, %startAlgorithm, %pullAlgorithm, %cancelAlgorithm, %highWaterMark, %sizeAlgorithm ) ◎ Perform ? SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm).
3.10. `ReadableByteStreamController^C ~class
`ReadableByteStreamController$C ~classは、 `ReadableStream$C の状態と`内部~queue$を制御できるようにする各種~methodを備える。 `ReadableStream$C を構築するとき、`下層~byte源$に対応して,操作するための `ReadableByteStreamController$C ~instanceが与えられる。 ◎ The ReadableByteStreamController class has methods that allow control of a ReadableStream's state and internal queue. When constructing a ReadableStream, the underlying byte source is given a corresponding ReadableByteStreamController instance to manipulate.
3.10.1. ~class定義
~INFORMATIVE`ReadableByteStreamController$C ~classは、 `ECMASCRIPT$r 風の構文で書くならば,次のようになる: ◎ If one were to write the ReadableByteStreamController class in something close to the syntax of [ECMASCRIPT], it would look like
class ReadableByteStreamController {
`constructor()$rbsc /*
常に投出する
◎
always throws
*/
get `byobRequest()$rbsc
get `desiredSize()$rbsc
`close()$rbsc
`enqueue(chunk)$rbsc
`error(e)$rbsc
}
3.10.2. 内部~slot
`ReadableByteStreamController$C の各~instanceは、次の一覧に述べる各種 内部~slotを伴って作成される: ◎ Instances of ReadableByteStreamController are created with the internal slots described in the following table:
内部~slot | 説明0(参考) |
---|---|
[[autoAllocateChunkSize]] | 自動的な~buffer割当て特色機能が可能化されているときは、正整数になり,~bufferに割当てる~sizeを指定する。 他の場合は ~undefined になる。 ◎ A positive integer, when the automatic buffer allocation feature is enabled. In that case, this value specifies the size of buffer to allocate. It is undefined otherwise. |
[[byobRequest]] | 現在の~BYOB~pull要請を表現している `ReadableStreamBYOBRequest$C ~instance。 ◎ A ReadableStreamBYOBRequest instance representing the current BYOB pull request |
[[cancelAlgorithm]] | 1 個の引数(取消-事由)をとり,~promiseを返す~algo — それは、要請された取消を`下層~源$に通信する。 ◎ A promise-returning algorithm, taking one argument (the cancel reason), which communicates a requested cancelation to the underlying source |
[[closeRequested]] | 真偽~flag — [ ~streamは その`下層~byte源$により~closeされたが,その内部~queueには 読取されていない`~chunk$がまだある ]かどうかを指示する。 ◎ A boolean flag indicating whether the stream has been closed by its underlying byte source, but still has chunks in its internal queue that have not yet been read |
[[controlledReadableByteStream]] | 制御先の `ReadableStream$C の~instance。 ◎ The ReadableStream instance controlled |
[[pullAgain]] | 真偽~flag — 更に~dataを~pullするために,~streamの仕組みにて`下層~byte源$の `pull()$src ~method~callが要請されたが、以前の~callがまだ実行-中にあるため,まだ~pullを行えない場合に ~true に設定される。 ◎ A boolean flag set to true if the stream’s mechanisms requested a call to the underlying byte source’s pull() method to pull more data, but the pull could not yet be done since a previous call is still executing |
[[pullAlgorithm]] | ~promiseを返す~algo — それは、`下層~源$から~dataを~pullする。 ◎ A promise-returning algorithm that pulls data from the underlying source |
[[pulling]] | 真偽~flag — `下層~byte源$の `pull()$src ~methodは実行-中にあるが,まだ充足されていない間は ~true に設定される。 これは、再入~callを防止するために利用される。 ◎ A boolean flag set to true while the underlying byte source’s pull() method is executing and has not yet fulfilled, used to prevent reentrant calls |
[[pendingPullIntos]] | 処理待ちの~BYOB~pull要請を表現している記述子たちからなる`~List$ 。 ◎ A List of descriptors representing pending BYOB pull requests |
[[queue]] | ~streamの[ `~chunk$たちからなる内部~queue ]を表現する`~List$ 。 ◎ A List representing the stream’s internal queue of chunks |
[[queueTotalSize]] | [[queue]] 内に格納されている すべての~chunkの,~byte数による合計~size ◎ The total size (in bytes) of all the chunks stored in [[queue]] |
[[started]] | 真偽~flag — [ `下層~源$が開始処理を完遂した ]かどうかを指示する。 ◎ A boolean flag indicating whether the underlying source has finished starting |
[[strategyHWM]] | ~streamの`~queuing策$の一部として,構築子に給された~number — それを境に,~streamが`下層~byte源$に`背圧$を適用することになるような。 【 HWM = High-Water Mark (限界水位) 】 ◎ A number supplied to the constructor as part of the stream’s queuing strategy, indicating the point at which the stream will apply backpressure to its underlying byte source |
注記: `ReadableByteStreamController$C の各~instanceは、 [[queue]], [[queueTotalSize]] 両~slotを有するが、これらに対しては `§個別~size付き~queue演算$の ほとんどの抽象~演算は利用しない — この~queueを操作する仕方は、仕様~内の他のものと~~異質なので。 代わりに, 2 つの~slotは、手動で一緒に更新する。 ◎ Although ReadableByteStreamController instances have [[queue]] and [[queueTotalSize]] slots, we do not use most of the abstract operations in §6.2 Queue-with-sizes operations on them, as the way in which we manipulate this queue is rather different than the others in the spec. Instead, we update the two slots together manually.
これは、将来,仕様を~refactorするときに整理されるであろう。 ◎ This might be cleaned up in a future spec refactoring.
3.10.3. `new ReadableByteStreamController()^rbsc
`ReadableByteStreamController()^rbsc 構築子は、直には利用できない — `ReadableByteStreamController$C ~instanceは、 `ReadableStream$C を構築する間に自動的に作成される。 ◎ The ReadableByteStreamController constructor cannot be used directly; ReadableByteStreamController instances are created automatically during ReadableStream construction.
- ~THROW `TypeError^b ◎ Throw a TypeError exception.
3.10.4. `ReadableByteStreamController^C ~prototypeの各種~prop
3.10.4.1. `get byobRequest^rbsc
`byobRequest^rbsc 取得子は、現在の~BYOB~pull要請を返す。 ◎ The byobRequest getter returns the current BYOB pull request.
- ~IF[ ! `IsReadableByteStreamController$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableByteStreamController(this) is false, throw a TypeError exception.
-
~IF[ ~this.[[byobRequest]] ~EQ ~undefined ]~AND[ ~this.[[pendingPullIntos]] は空でない ]: ◎ If this.[[byobRequest]] is undefined and this.[[pendingPullIntos]] is not empty,
- %firstDescriptor ~LET ~this.[[pendingPullIntos]] の最初の要素 ◎ Let firstDescriptor be the first element of this.[[pendingPullIntos]].
- %view ~LET ! `Construct$A( `~Uint8Array$, « %firstDescriptor.[[buffer]], ( %firstDescriptor.[[byteOffset]] + %firstDescriptor.[[bytesFilled]] ), ( %firstDescriptor.[[byteLength]] − %firstDescriptor.[[bytesFilled]] ) » ) ◎ Let view be ! Construct(%Uint8Array%, « firstDescriptor.[[buffer]], firstDescriptor.[[byteOffset]] + firstDescriptor.[[bytesFilled]], firstDescriptor.[[byteLength]] − firstDescriptor.[[bytesFilled]] »).
- %byobRequest ~LET `ObjectCreate$A( `ReadableStreamBYOBRequest$C の `prototype^c ~propの元の値 ) ◎ Let byobRequest be ObjectCreate(the original value of ReadableStreamBYOBRequest's prototype property).
- ! `SetUpReadableStreamBYOBRequest$A( %byobRequest, ~this, %view ) ◎ Perform ! SetUpReadableStreamBYOBRequest(byobRequest, this, view).
- ~this.[[byobRequest]] ~SET %byobRequest ◎ Set this.[[byobRequest]] to byobRequest.
- ~RET ~this.[[byobRequest]] ◎ Return this.[[byobRequest]].
3.10.4.2. `get desiredSize^rbsc
`desiredSize^rbsc 取得子は、制御先の`~streamの内部~queueの残り~size$を返す。 それは、負にもなり得る — ~queueを溢れるときは。 `下層~源$が`背圧$をいつどのように適用するかを決定するときは、この情報が利用されるべきである。 ◎ The desiredSize getter returns the desired size to fill the controlled stream’s internal queue. It can be negative, if the queue is over-full. An underlying source ought to use this information to determine when and how to apply backpressure.
- ~IF[ ! `IsReadableByteStreamController$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableByteStreamController(this) is false, throw a TypeError exception.
- ~RET ! `ReadableByteStreamControllerGetDesiredSize$A( ~this ) ◎ Return ! ReadableByteStreamControllerGetDesiredSize(this).
3.10.4.3. `close()^rbsc
`close()^rbsc ~methodは、制御先の可読~streamを~closeする。 `消費器$は依然として,それまでに~enqueueされた`~chunk$たちを~streamから読取できるが、それらが読取されたなら,~streamは~closeされる。 ◎ The close method will close the controlled readable stream. Consumers will still be able to read any previously-enqueued chunks from the stream, but once those are read, the stream will become closed.
- ~IF[ ! `IsReadableByteStreamController$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableByteStreamController(this) is false, throw a TypeError exception.
- ~IF[ ~this.[[closeRequested]] ~EQ ~true ] ⇒ ~THROW `TypeError^b ◎ If this.[[closeRequested]] is true, throw a TypeError exception.
- ~IF[ ~this.[[controlledReadableByteStream]].[[state]] ~NEQ `readable^l ] ⇒ ~THROW `TypeError^b ◎ If this.[[controlledReadableByteStream]].[[state]] is not "readable", throw a TypeError exception.
- ? `ReadableByteStreamControllerClose$A( ~this ) ◎ Perform ? ReadableByteStreamControllerClose(this).
3.10.4.4. `enqueue(chunk)^rbsc
`enqueue()^rbsc ~methodは、所与の`~chunk$を制御先の可読~stream内に~enqueueする。 ◎ The enqueue method will enqueue a given chunk in the controlled readable stream.
- ~IF[ ! `IsReadableByteStreamController$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableByteStreamController(this) is false, throw a TypeError exception.
- ~IF[ ~this.[[closeRequested]] ~EQ ~true ] ⇒ ~THROW `TypeError^b ◎ If this.[[closeRequested]] is true, throw a TypeError exception.
- ~IF[ ~this.[[controlledReadableByteStream]].[[state]] ~NEQ `readable^l ] ⇒ ~THROW `TypeError^b ◎ If this.[[controlledReadableByteStream]].[[state]] is not "readable", throw a TypeError exception.
- ~IF[ `Type$A( %chunk ) ~NEQ `Object^b ] ⇒ ~THROW `TypeError^b ◎ If Type(chunk) is not Object, throw a TypeError exception.
- ~IF[ %chunk は [[ViewedArrayBuffer]] 内部~slotを持たない ] ⇒ ~THROW `TypeError^b ◎ If chunk does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception.
- ~IF[ ! `IsDetachedBuffer$A( %chunk.[[ViewedArrayBuffer]] ) ~EQ ~true ] ⇒ ~THROW `TypeError^b ◎ If ! IsDetachedBuffer(chunk.[[ViewedArrayBuffer]]) is true, throw a TypeError exception.
- ~RET ! `ReadableByteStreamControllerEnqueue$A( ~this, %chunk ) ◎ Return ! ReadableByteStreamControllerEnqueue(this, chunk).
3.10.4.5. `error(e)^rbsc
`error()^rbsc ~methodは、可読~streamを~errorにする — 以降の相互作用は、すべて所与の~error %e で失敗させる。 ◎ The error method will error the readable stream, making all future interactions with it fail with the given error e.
- ~IF[ ! `IsReadableByteStreamController$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableByteStreamController(this) is false, throw a TypeError exception.
- ! `ReadableByteStreamControllerError$A( ~this, %e ) ◎ Perform ! ReadableByteStreamControllerError(this, e).
3.10.5. 可読 ~streamの~BYOB制御器の各種 内部~method
以下のものは、各 `ReadableByteStreamController$C ~instanceにより実装される,追加の内部~methodである。 可読~streamの実装は、[ それら, または 既定の制御器~用の それらに相当するもの ]いずれかを多形態的に~callすることになる。 ◎ The following are additional internal methods implemented by each ReadableByteStreamController instance. The readable stream implementation will polymorphically call to either these or their counterparts for default controllers.
3.10.5.1. `[[CancelSteps]]$( %reason )
-
~IF[ ~this.[[pendingPullIntos]] は空でない ]: ◎ If this.[[pendingPullIntos]] is not empty,
- %firstDescriptor ~LET ~this.[[pendingPullIntos]] の最初の要素 ◎ Let firstDescriptor be the first element of this.[[pendingPullIntos]].
- %firstDescriptor.[[bytesFilled]] ~SET `0^b ◎ Set firstDescriptor.[[bytesFilled]] to 0.
- ! `ResetQueue$A( ~this ) ◎ Perform ! ResetQueue(this).
- ~RET 次を遂行した結果 ⇒ ~this.[[cancelAlgorithm]]( %reason ) ◎ Return the result of performing this.[[cancelAlgorithm]], passing in reason.
3.10.5.2. `[[PullSteps]]$( %forAuthorCode )
- %stream ~LET ~this.[[controlledReadableByteStream]] ◎ Let stream be this.[[controlledReadableByteStream]].
- ~Assert: ! `ReadableStreamHasDefaultReader$A( %stream ) ~EQ ~true ◎ Assert: ! ReadableStreamHasDefaultReader(stream) is true.
-
~IF[ ~this.[[queueTotalSize]] ~GT `0^b ]: ◎ If this.[[queueTotalSize]] > 0,
- ~Assert: ! `ReadableStreamGetNumReadRequests$A( %stream ) ~EQ `0^b: ◎ Assert: ! ReadableStreamGetNumReadRequests(stream) is 0.
- %entry ~LET ~this.[[queue]] の最初の要素 ◎ Let entry be the first element of this.[[queue]].
- ~this.[[queue]] から %entry を除去する — 後続の要素たちは~~先頭へ一つずらす ◎ Remove entry from this.[[queue]], shifting all other elements downward (so that the second becomes the first, and so on).
- ~this.[[queueTotalSize]] ~DECBY %entry.[[byteLength]] ◎ Set this.[[queueTotalSize]] to this.[[queueTotalSize]] − entry.[[byteLength]].
- ! `ReadableByteStreamControllerHandleQueueDrain$A( ~this ) ◎ Perform ! ReadableByteStreamControllerHandleQueueDrain(this).
- %view ~LET ! `Construct$A( `~Uint8Array$, « %entry.[[buffer]], %entry.[[byteOffset]], %entry.[[byteLength]] » ) ◎ Let view be ! Construct(%Uint8Array%, « entry.[[buffer]], entry.[[byteOffset]], entry.[[byteLength]] »).
- ~RET ! `ReadableStreamCreateReadResult$A( %view, ~false, %forAuthorCode ) で`解決される~promise$ ◎ Return a promise resolved with ! ReadableStreamCreateReadResult(view, false, forAuthorCode).
- %autoAllocateChunkSize ~LET ~this.[[autoAllocateChunkSize]] ◎ Let autoAllocateChunkSize be this.[[autoAllocateChunkSize]].
-
~IF[ %autoAllocateChunkSize ~NEQ ~undefined ]: ◎ If autoAllocateChunkSize is not undefined,
- %buffer ~LET `Construct$A( `~ArrayBuffer$, « %autoAllocateChunkSize » ) ◎ Let buffer be Construct(%ArrayBuffer%, « autoAllocateChunkSize »).
- ~IF[ %buffer は`中途完了$である ] ⇒ ~RET %buffer.[[Value]] で`却下される~promise$ ◎ If buffer is an abrupt completion, return a promise rejected with buffer.[[Value]].
- %pullIntoDescriptor ~LET `~Record$ { [[buffer]]: %buffer.[[Value]], [[byteOffset]]: `0^b, [[byteLength]]: %autoAllocateChunkSize, [[bytesFilled]]: `0^b, [[elementSize]]: `1^b, [[ctor]]: `~Uint8Array$, [[readerType]]: `default^l } ◎ Let pullIntoDescriptor be Record {[[buffer]]: buffer.[[Value]], [[byteOffset]]: 0, [[byteLength]]: autoAllocateChunkSize, [[bytesFilled]]: 0, [[elementSize]]: 1, [[ctor]]: %Uint8Array%, [[readerType]]: "default"}.
- ~this.[[pendingPullIntos]] の~~末尾に %pullIntoDescriptor を付加する ◎ Append pullIntoDescriptor as the last element of this.[[pendingPullIntos]].
- %promise ~LET ! `ReadableStreamAddReadRequest$A( %stream, %forAuthorCode ) ◎ Let promise be ! ReadableStreamAddReadRequest(stream, forAuthorCode).
- ! `ReadableByteStreamControllerCallPullIfNeeded$A( ~this ) ◎ Perform ! ReadableByteStreamControllerCallPullIfNeeded(this).
- ~RET %promise ◎ Return promise.
3.11. `ReadableStreamBYOBRequest^C ~class
`ReadableStreamBYOBRequest$C ~classは、 `ReadableByteStreamController$C 内の[ 中へ~pullする要請 ]を表現する。 ◎ The ReadableStreamBYOBRequest class represents a pull into request in a ReadableByteStreamController.
3.11.1. ~class定義
~INFORMATIVE`ReadableStreamBYOBRequest$C ~classは、 `ECMASCRIPT$r 風の構文で書くならば,次のようになる: ◎ If one were to write the ReadableStreamBYOBRequest class in something close to the syntax of [ECMASCRIPT], it would look like
class ReadableStreamBYOBRequest { `constructor(controller, view)$bbrq get `view()$bbrq `respond(bytesWritten)$bbrq `respondWithNewView(view)$bbrq }
3.11.2. 内部~slot
`ReadableStreamBYOBRequest$C の各~instanceは、次の一覧に述べる各種 内部~slotを伴って作成される: ◎ Instances of ReadableStreamBYOBRequest are created with the internal slots described in the following table:
内部~slot | 説明0(参考) |
---|---|
[[associatedReadableByteStreamController]] | 親の `ReadableByteStreamController$C ~instance ◎ The parent ReadableByteStreamController instance |
[[view]] | 行先~領域を表現する `Uint8Array$I — 制御器は、生成される~dataをその領域に書込できる。 ◎ A typed array representing the destination region to which the controller can write generated data |
3.11.3. `new ReadableStreamBYOBRequest()^m
- ~THROW `TypeError^b ◎ Throw a TypeError exception.
3.11.4. `ReadableStreamBYOBRequest^C ~prototypeの各種~prop
3.11.4.1. `get view^m
- ~IF[ ! `IsReadableStreamBYOBRequest$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStreamBYOBRequest(this) is false, throw a TypeError exception.
- ~RET ~this.[[view]] ◎ Return this.[[view]].
3.11.4.2. `respond(bytesWritten)^m
- ~IF[ ! `IsReadableStreamBYOBRequest$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStreamBYOBRequest(this) is false, throw a TypeError exception.
- ~IF[ ~this.[[associatedReadableByteStreamController]] ~EQ ~undefined ] ⇒ ~THROW `TypeError^b ◎ If this.[[associatedReadableByteStreamController]] is undefined, throw a TypeError exception.
- ~IF[ ! `IsDetachedBuffer$A( ~this.[[view]].[[ViewedArrayBuffer]] ) ~EQ ~true ] ⇒ ~THROW `TypeError^b ◎ If ! IsDetachedBuffer(this.[[view]].[[ViewedArrayBuffer]]) is true, throw a TypeError exception.
- ~RET ? `ReadableByteStreamControllerRespond$A( ~this.[[associatedReadableByteStreamController]], %bytesWritten ) ◎ Return ? ReadableByteStreamControllerRespond(this.[[associatedReadableByteStreamController]], bytesWritten).
3.11.4.3. `respondWithNewView(view)^m
- ~IF[ ! `IsReadableStreamBYOBRequest$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsReadableStreamBYOBRequest(this) is false, throw a TypeError exception.
- ~IF[ ~this.[[associatedReadableByteStreamController]] ~EQ ~undefined ] ⇒ ~THROW `TypeError^b ◎ If this.[[associatedReadableByteStreamController]] is undefined, throw a TypeError exception.
- ~IF[ `Type$A( %view ) ~NEQ `Object^b ] ⇒ ~THROW `TypeError^b ◎ If Type(view) is not Object, throw a TypeError exception.
- ~IF[ %view は [[ViewedArrayBuffer]] 内部~slotを持たない ] ⇒ ~THROW `TypeError^b ◎ If view does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception.
- ~IF[ ! `IsDetachedBuffer$A( %view.[[ViewedArrayBuffer]] ) ~EQ ~true ] ⇒ ~THROW `TypeError^b ◎ If ! IsDetachedBuffer(view.[[ViewedArrayBuffer]]) is true, throw a TypeError exception.
- ~RET ? `ReadableByteStreamControllerRespondWithNewView$A( ~this.[[associatedReadableByteStreamController]], %view) ◎ Return ? ReadableByteStreamControllerRespondWithNewView(this.[[associatedReadableByteStreamController]], view).
3.12. 可読~streamの~BYOB制御器~用の抽象~演算
3.12.1. `IsReadableStreamBYOBRequest( x )^A
- ~IF[ `Type$A(%x) ~NEQ `Object^b ] ⇒ ~RET ~false ◎ If Type(x) is not Object, return false.
- ~IF[ %x は [[associatedReadableByteStreamController]] 内部~slotを持たない ] ⇒ ~RET ~false ◎ If x does not have an [[associatedReadableByteStreamController]] internal slot, return false.
- ~RET ~true ◎ Return true.
3.12.2. `IsReadableByteStreamController( x )^A
- ~IF[ `Type$A(%x) ~NEQ `Object^b ] ⇒ ~RET ~false ◎ If Type(x) is not Object, return false.
- ~IF[ %x は [[controlledReadableByteStream]] 内部~slotを持たない ] ⇒ ~RET ~false ◎ If x does not have an [[controlledReadableByteStream]] internal slot, return false.
- ~RET ~true ◎ Return true.
3.12.3. `ReadableByteStreamControllerCallPullIfNeeded( controller )^A
- %shouldPull ~LET ! `ReadableByteStreamControllerShouldCallPull$A( %controller ) ◎ Let shouldPull be ! ReadableByteStreamControllerShouldCallPull(controller).
- ~IF[ %shouldPull ~EQ ~false ] ⇒ ~RET ◎ If shouldPull is false, return.
-
~IF[ %controller.[[pulling]] ~EQ ~true ]: ◎ If controller.[[pulling]] is true,
- %controller.[[pullAgain]] ~SET ~true ◎ Set controller.[[pullAgain]] to true.
- ~RET ◎ Return.
- ~Assert: %controller.[[pullAgain]] ~EQ ~false ◎ Assert: controller.[[pullAgain]] is false.
- %controller.[[pulling]] ~SET ~true ◎ Set controller.[[pulling]] to true.
-
%pullPromise ~LET 次を遂行した結果 ⇒ %controller.[[pullAlgorithm]]() ◎ Let pullPromise be the result of performing controller.[[pullAlgorithm]].
-
%pullPromise の`充足-時$には: ◎ Upon fulfillment of pullPromise,
- %controller.[[pulling]] ~SET ~false ◎ Set controller.[[pulling]] to false.
-
~IF[ %controller.[[pullAgain]] ~EQ ~true ]: ◎ If controller.[[pullAgain]] is true,
- %controller.[[pullAgain]] ~SET ~false ◎ Set controller.[[pullAgain]] to false.
- ! `ReadableByteStreamControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
-
事由 %e による %pullPromise の`却下-時$には: ◎ Upon rejection of pullPromise with reason e,
- ! `ReadableByteStreamControllerError$A( %controller, %e ) ◎ Perform ! ReadableByteStreamControllerError(controller, e).
-
3.12.4. `ReadableByteStreamControllerClearPendingPullIntos( controller )^A
- ! `ReadableByteStreamControllerInvalidateBYOBRequest$A( %controller ) ◎ Perform ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).
- %controller.[[pendingPullIntos]] ~SET 新たな空`~List$ ◎ Set controller.[[pendingPullIntos]] to a new empty List.
3.12.5. `ReadableByteStreamControllerClose( controller )^A
- %stream ~LET %controller.[[controlledReadableByteStream]] ◎ Let stream be controller.[[controlledReadableByteStream]].
- ~Assert: %controller.[[closeRequested]] ~EQ ~false ◎ Assert: controller.[[closeRequested]] is false.
- ~Assert: %stream.[[state]] ~EQ `readable^l ◎ Assert: stream.[[state]] is "readable".
-
~IF[ %controller.[[queueTotalSize]] ~GT `0^b ]: ◎ If controller.[[queueTotalSize]] > 0,
- %controller.[[closeRequested]] ~SET ~true ◎ Set controller.[[closeRequested]] to true.
- ~RET ◎ Return.
-
~IF[ %controller.[[pendingPullIntos]] は空でない ]: ◎ If controller.[[pendingPullIntos]] is not empty,
- %firstPendingPullInto ~LET %controller.[[pendingPullIntos]] の最初の要素 ◎ Let firstPendingPullInto be the first element of controller.[[pendingPullIntos]].
-
~IF[ %firstPendingPullInto.[[bytesFilled]] ~GT `0^b ]: ◎ If firstPendingPullInto.[[bytesFilled]] > 0,
- %e ~LET 新たな `TypeError^b 例外 ◎ Let e be a new TypeError exception.
- ! `ReadableByteStreamControllerError$A( %controller, %e ) ◎ Perform ! ReadableByteStreamControllerError(controller, e).
- ~THROW %e ◎ Throw e.
- ! `ReadableStreamClose$A( %stream ) ◎ Perform ! ReadableStreamClose(stream).
3.12.6. `ReadableByteStreamControllerCommitPullIntoDescriptor( stream, pullIntoDescriptor )^A
- ~Assert: %stream.[[state]] ~NEQ `errored^l ◎ Assert: stream.[[state]] is not "errored".
- %done ~LET ~false ◎ Let done be false.
-
~IF[ %stream.[[state]] ~EQ `closed^l ]: ◎ If stream.[[state]] is "closed",
- ~Assert: %pullIntoDescriptor.[[bytesFilled]] ~EQ `0^b ◎ Assert: pullIntoDescriptor.[[bytesFilled]] is 0.
- %done ~SET ~true ◎ Set done to true.
- %filledView ~LET ! `ReadableByteStreamControllerConvertPullIntoDescriptor$A( %pullIntoDescriptor ) ◎ Let filledView be ! ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
-
~IF[ %pullIntoDescriptor.[[readerType]] ~EQ `default^l ]: ◎ If pullIntoDescriptor.[[readerType]] is "default",
- ! `ReadableStreamFulfillReadRequest$A( %stream, %filledView, %done ) ◎ Perform ! ReadableStreamFulfillReadRequest(stream, filledView, done).
-
~ELSE: ◎ Otherwise,
- ~Assert: %pullIntoDescriptor.[[readerType]] ~EQ `byob^l : ◎ Assert: pullIntoDescriptor.[[readerType]] is "byob".
- ! `ReadableStreamFulfillReadIntoRequest$A( %stream, %filledView, %done ) ◎ Perform ! ReadableStreamFulfillReadIntoRequest(stream, filledView, done).
3.12.7. `ReadableByteStreamControllerConvertPullIntoDescriptor( pullIntoDescriptor )^A
- %bytesFilled ~LET %pullIntoDescriptor.[[bytesFilled]] ◎ Let bytesFilled be pullIntoDescriptor.[[bytesFilled]].
- %elementSize ~LET %pullIntoDescriptor.[[elementSize]] ◎ Let elementSize be pullIntoDescriptor.[[elementSize]].
- ~Assert: %bytesFilled ~LTE %pullIntoDescriptor.[[byteLength]] ◎ Assert: bytesFilled ≤ pullIntoDescriptor.[[byteLength]].
- ~Assert: ( %bytesFilled ~mod %elementSize ) ~EQ `0^b ◎ Assert: bytesFilled mod elementSize is 0.
- ~RET ! `Construct$A( %pullIntoDescriptor.[[ctor]], « %pullIntoDescriptor.[[buffer]], %pullIntoDescriptor.[[byteOffset]], %bytesFilled ÷ %elementSize » ) ◎ Return ! Construct(pullIntoDescriptor.[[ctor]], « pullIntoDescriptor.[[buffer]], pullIntoDescriptor.[[byteOffset]], bytesFilled ÷ elementSize »).
3.12.8. `ReadableByteStreamControllerEnqueue( controller, chunk )^A
- %stream ~LET %controller.[[controlledReadableByteStream]] ◎ Let stream be controller.[[controlledReadableByteStream]].
- ~Assert: %controller.[[closeRequested]] ~EQ ~false ◎ Assert: controller.[[closeRequested]] is false.
- ~Assert: %stream.[[state]] ~EQ `readable^l ◎ Assert: stream.[[state]] is "readable".
- %buffer ~LET %chunk.[[ViewedArrayBuffer]] ◎ Let buffer be chunk.[[ViewedArrayBuffer]].
- %byteOffset ~LET %chunk.[[ByteOffset]] ◎ Let byteOffset be chunk.[[ByteOffset]].
- %byteLength ~LET %chunk.[[ByteLength]] ◎ Let byteLength be chunk.[[ByteLength]].
- %transferredBuffer ~LET ! `TransferArrayBuffer$A( %buffer ) ◎ Let transferredBuffer be ! TransferArrayBuffer(buffer).
-
~IF[ ! `ReadableStreamHasDefaultReader$A( %stream ) ~EQ ~true ]: ◎ If ! ReadableStreamHasDefaultReader(stream) is true
-
~IF[ ! `ReadableStreamGetNumReadRequests$A( %stream ) ~EQ `0^b ]: ◎ If ! ReadableStreamGetNumReadRequests(stream) is 0,
- ! `ReadableByteStreamControllerEnqueueChunkToQueue$A( %controller, %transferredBuffer, %byteOffset, %byteLength ) ◎ Perform ! ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength).
-
~ELSE: ◎ Otherwise,
- ~Assert: %controller.[[queue]] は空である ◎ Assert: controller.[[queue]] is empty.
- %transferredView ~LET ! `Construct$A( `~Uint8Array$, « %transferredBuffer, %byteOffset, %byteLength » ) ◎ Let transferredView be ! Construct(%Uint8Array%, « transferredBuffer, byteOffset, byteLength »).
- ! `ReadableStreamFulfillReadRequest$A( %stream, %transferredView, ~false ) ◎ Perform ! ReadableStreamFulfillReadRequest(stream, transferredView, false).
-
-
~ELIF ! `ReadableStreamHasBYOBReader$A( %stream ) ~EQ ~true : ◎ Otherwise, if ! ReadableStreamHasBYOBReader(stream) is true,
- ! `ReadableByteStreamControllerEnqueueChunkToQueue$A( %controller, %transferredBuffer, %byteOffset, %byteLength ) ◎ Perform ! ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength).
- ! `ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue$A( %controller ) ◎ Perform ! ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
-
~ELSE: ◎ Otherwise,
- ~Assert: ! `IsReadableStreamLocked$A( %stream ) ~EQ ~false ◎ Assert: ! IsReadableStreamLocked(stream) is false.
- ! `ReadableByteStreamControllerEnqueueChunkToQueue$A( %controller, %transferredBuffer, %byteOffset, %byteLength ) ◎ Perform ! ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength).
- ! `ReadableByteStreamControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
3.12.9. `ReadableByteStreamControllerEnqueueChunkToQueue( controller, buffer, byteOffset, byteLength )^A
- %controller.[[queue]] の~~末尾に `~Record$ { {[[buffer]]: %buffer, [[byteOffset]]: %byteOffset, [[byteLength]]: %byteLength } を付加する ◎ Append Record {[[buffer]]: buffer, [[byteOffset]]: byteOffset, [[byteLength]]: byteLength} as the last element of controller.[[queue]].
- %controller.[[queueTotalSize]] ~INCBY %byteLength ◎ Add byteLength to controller.[[queueTotalSize]].
3.12.10. `ReadableByteStreamControllerError( controller, e )^A
- %stream ~LET %controller.[[controlledReadableByteStream]] ◎ Let stream be controller.[[controlledReadableByteStream]].
- ~IF[ %stream.[[state]] ~NEQ `readable^l ] ⇒ ~RET ◎ If stream.[[state]] is not "readable", return.
- ! `ReadableByteStreamControllerClearPendingPullIntos$A( %controller ) ◎ Perform ! ReadableByteStreamControllerClearPendingPullIntos(controller).
- ! `ResetQueue$A( %controller ) ◎ Perform ! ResetQueue(controller).
- ! `ReadableStreamError$A( %stream, %e ) ◎ Perform ! ReadableStreamError(stream, e).
3.12.11. `ReadableByteStreamControllerFillHeadPullIntoDescriptor( controller, size, pullIntoDescriptor )^A
- ~Assert:[ %controller.[[pendingPullIntos]] は空である ]~OR[ %controller.[[pendingPullIntos]] の最初の要素 ~EQ %pullIntoDescriptor ] ◎ Assert: either controller.[[pendingPullIntos]] is empty, or the first element of controller.[[pendingPullIntos]] is pullIntoDescriptor.
- ! `ReadableByteStreamControllerInvalidateBYOBRequest$A( %controller ) ◎ Perform ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).
- %pullIntoDescriptor.[[bytesFilled]] ~INCBY %size ◎ Set pullIntoDescriptor.[[bytesFilled]] to pullIntoDescriptor.[[bytesFilled]] + size.
3.12.12. `ReadableByteStreamControllerFillPullIntoDescriptorFromQueue( controller, pullIntoDescriptor )^A
- %elementSize ~LET %pullIntoDescriptor.[[elementSize]] ◎ Let elementSize be pullIntoDescriptor.[[elementSize]].
- %currentAlignedBytes ~LET ( %pullIntoDescriptor.[[bytesFilled]] − ( %pullIntoDescriptor.[[bytesFilled]] ~mod %elementSize ) ) ◎ Let currentAlignedBytes be pullIntoDescriptor.[[bytesFilled]] − (pullIntoDescriptor.[[bytesFilled]] mod elementSize).
- %maxBytesToCopy ~LET `min$( %controller.[[queueTotalSize]], ( %pullIntoDescriptor.[[byteLength]] − %pullIntoDescriptor.[[bytesFilled]] ) ) ◎ Let maxBytesToCopy be min(controller.[[queueTotalSize]], pullIntoDescriptor.[[byteLength]] − pullIntoDescriptor.[[bytesFilled]]).
- %maxBytesFilled ~LET ( %pullIntoDescriptor.[[bytesFilled]] + %maxBytesToCopy ) ◎ Let maxBytesFilled be pullIntoDescriptor.[[bytesFilled]] + maxBytesToCopy.
- %maxAlignedBytes ~LET ( %maxBytesFilled − ( %maxBytesFilled ~mod %elementSize ) ) ◎ Let maxAlignedBytes be maxBytesFilled − (maxBytesFilled mod elementSize).
- %totalBytesToCopyRemaining ~LET %maxBytesToCopy ◎ Let totalBytesToCopyRemaining be maxBytesToCopy.
- %ready ~LET ~false ◎ Let ready be false.
-
~IF[ %maxAlignedBytes ~GT %currentAlignedBytes ]: ◎ If maxAlignedBytes > currentAlignedBytes,
- %totalBytesToCopyRemaining ~SET %maxAlignedBytes − %pullIntoDescriptor.[[bytesFilled]] ◎ Set totalBytesToCopyRemaining to maxAlignedBytes − pullIntoDescriptor.[[bytesFilled]].
- %ready ~SET ~true ◎ Set ready to true.
- %queue ~LET %controller.[[queue]] ◎ Let queue be controller.[[queue]].
-
~WHILE %totalBytesToCopyRemaining ~GT `0^b: ◎ Repeat the following steps while totalBytesToCopyRemaining > 0,
- %headOfQueue ~LET %queue の最初の要素 ◎ Let headOfQueue be the first element of queue.
- %bytesToCopy ~LET `min$( %totalBytesToCopyRemaining, %headOfQueue.[[byteLength]] ) ◎ Let bytesToCopy be min(totalBytesToCopyRemaining, headOfQueue.[[byteLength]]).
- %destStart ~LET ( %pullIntoDescriptor.[[byteOffset]] + %pullIntoDescriptor.[[bytesFilled]] ) ◎ Let destStart be pullIntoDescriptor.[[byteOffset]] + pullIntoDescriptor.[[bytesFilled]].
- ! `CopyDataBlockBytes$A( %pullIntoDescriptor.[[buffer]].[[ArrayBufferData]], %destStart, %headOfQueue.[[buffer]].[[ArrayBufferData]], %headOfQueue.[[byteOffset]], %bytesToCopy ) ◎ Perform ! CopyDataBlockBytes(pullIntoDescriptor.[[buffer]].[[ArrayBufferData]], destStart, headOfQueue.[[buffer]].[[ArrayBufferData]], headOfQueue.[[byteOffset]], bytesToCopy).
-
~IF[ %headOfQueue.[[byteLength]] ~EQ %bytesToCopy ]: ◎ If headOfQueue.[[byteLength]] is bytesToCopy,
- %queue の最初の要素を除去する — 後続の要素たちは~~先頭へ一つずらす ◎ Remove the first element of queue, shifting all other elements downward (so that the second becomes the first, and so on).
-
~ELSE: ◎ Otherwise,
- %headOfQueue.[[byteOffset]] ~INCBY %bytesToCopy ◎ Set headOfQueue.[[byteOffset]] to headOfQueue.[[byteOffset]] + bytesToCopy.
- %headOfQueue.[[byteLength]] ~DECBY %bytesToCopy ◎ Set headOfQueue.[[byteLength]] to headOfQueue.[[byteLength]] − bytesToCopy.
- %controller.[[queueTotalSize]] ~DECBY %bytesToCopy ◎ Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]] − bytesToCopy.
- ! `ReadableByteStreamControllerFillHeadPullIntoDescriptor$A( %controller, %bytesToCopy, %pullIntoDescriptor ) ◎ Perform ! ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesToCopy, pullIntoDescriptor).
- %totalBytesToCopyRemaining ~DECBY %bytesToCopy ◎ Set totalBytesToCopyRemaining to totalBytesToCopyRemaining − bytesToCopy.
-
~IF[ %ready ~EQ ~false ]: ◎ If ready is false,
- ~Assert: %controller.[[queueTotalSize]] ~EQ `0^b ◎ Assert: controller.[[queueTotalSize]] is 0.
- ~Assert: %pullIntoDescriptor.[[bytesFilled]] ~GT `0^b ◎ Assert: pullIntoDescriptor.[[bytesFilled]] > 0.
- ~Assert: %pullIntoDescriptor.[[bytesFilled]] ~LT %pullIntoDescriptor.[[elementSize]] ◎ Assert: pullIntoDescriptor.[[bytesFilled]] < pullIntoDescriptor.[[elementSize]].
- ~RET %ready ◎ Return ready.
3.12.13. `ReadableByteStreamControllerGetDesiredSize( controller )^A
- %stream ~LET %controller.[[controlledReadableByteStream]] ◎ Let stream be controller.[[controlledReadableByteStream]].
- %state ~LET %stream.[[state]] ◎ Let state be stream.[[state]].
- ~IF[ %state ~EQ `errored^l ] ⇒ ~RET `null^b ◎ If state is "errored", return null.
- ~IF[ %state ~EQ `closed^l ] ⇒ ~RET `0^b ◎ If state is "closed", return 0.
- ~RET %controller.[[strategyHWM]] − %controller.[[queueTotalSize]] ◎ Return controller.[[strategyHWM]] − controller.[[queueTotalSize]].
3.12.14. `ReadableByteStreamControllerHandleQueueDrain( controller )^A
- ~Assert: %controller.[[controlledReadableByteStream]].[[state]] ~EQ `readable^l ◎ Assert: controller.[[controlledReadableByteStream]].[[state]] is "readable".
-
~IF[ %controller.[[queueTotalSize]] ~EQ `0^b ]~AND[ %controller.[[closeRequested]] ~EQ ~true ]: ◎ If controller.[[queueTotalSize]] is 0 and controller.[[closeRequested]] is true,
- ! `ReadableStreamClose$A( %controller.[[controlledReadableByteStream]] ) ◎ Perform ! ReadableStreamClose(controller.[[controlledReadableByteStream]]).
-
~ELSE: ◎ Otherwise,
- ! `ReadableByteStreamControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
3.12.15. `ReadableByteStreamControllerInvalidateBYOBRequest( controller )^A
- ~IF[ %controller.[[byobRequest]] ~EQ ~undefined ] ⇒ ~RET ◎ If controller.[[byobRequest]] is undefined, return.
- %controller.[[byobRequest]].[[associatedReadableByteStreamController]] ~SET ~undefined ◎ Set controller.[[byobRequest]].[[associatedReadableByteStreamController]] to undefined.
- %controller.[[byobRequest]].[[view]] ~SET ~undefined ◎ Set controller.[[byobRequest]].[[view]] to undefined.
- %controller.[[byobRequest]] ~SET ~undefined ◎ Set controller.[[byobRequest]] to undefined.
3.12.16. `ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue( controller )^A
- ~Assert: %controller.[[closeRequested]] ~EQ ~false ◎ Assert: controller.[[closeRequested]] is false.
-
~WHILE %controller.[[pendingPullIntos]] は空でない: ◎ Repeat the following steps while controller.[[pendingPullIntos]] is not empty,
- ~IF[ %controller.[[queueTotalSize]] ~EQ `0^b ] ⇒ ~RET ◎ If controller.[[queueTotalSize]] is 0, return.
- %pullIntoDescriptor ~LET %controller.[[pendingPullIntos]] の最初の要素 ◎ Let pullIntoDescriptor be the first element of controller.[[pendingPullIntos]].
-
~IF[ ! `ReadableByteStreamControllerFillPullIntoDescriptorFromQueue$A( %controller, %pullIntoDescriptor ) ~EQ ~true ]: ◎ If ! ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) is true,
- ! `ReadableByteStreamControllerShiftPendingPullInto$A( %controller ) ◎ Perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).
- ! `ReadableByteStreamControllerCommitPullIntoDescriptor$A( %controller.[[controlledReadableByteStream]], %pullIntoDescriptor) ◎ Perform ! ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[controlledReadableByteStream]], pullIntoDescriptor).
3.12.17. `ReadableByteStreamControllerPullInto( controller, view, forAuthorCode )^A
- %stream ~LET %controller.[[controlledReadableByteStream]] ◎ Let stream be controller.[[controlledReadableByteStream]].
- %elementSizem ~LET `1^b ◎ Let elementSize be 1.
- %ctor ~LET ~DataView ◎ Let ctor be %DataView%.
- ~IF[ %view は [[TypedArrayName]] 内部~slotを持つ(すなわち, `DataView$I ではない) ] ⇒ ( %elementSizem, %ctor ) ~SET %view.[[TypedArrayName]] に対し 有型~配列 構築子 table に指定される ( 要素~size, 構築子 ) ◎ If view has a [[TypedArrayName]] internal slot (i.e., it is not a DataView), ◎ Set elementSize to the element size specified in the typed array constructors table for view.[[TypedArrayName]]. ◎ Set ctor to the constructor specified in the typed array constructors table for view.[[TypedArrayName]].
- %byteOffset ~LET %view.[[ByteOffset]] ◎ Let byteOffset be view.[[ByteOffset]].
- %byteLength ~LET %view.[[ByteLength]] ◎ Let byteLength be view.[[ByteLength]].
- %buffer ~LET ! `TransferArrayBuffer$A( %view.[[ViewedArrayBuffer]] ) ◎ Let buffer be ! TransferArrayBuffer(view.[[ViewedArrayBuffer]]).
- %pullIntoDescriptor ~LET `~Record$ { [[buffer]]: %buffer, [[byteOffset]]: %byteOffset, [[byteLength]]: %byteLength, [[bytesFilled]]: `0^b, [[elementSize]]: %elementSize, [[ctor]]: %ctor, [[readerType]]: `byob^l } ◎ Let pullIntoDescriptor be Record {[[buffer]]: buffer, [[byteOffset]]: byteOffset, [[byteLength]]: byteLength, [[bytesFilled]]: 0, [[elementSize]]: elementSize, [[ctor]]: ctor, [[readerType]]: "byob"}.
-
~IF[ %controller.[[pendingPullIntos]] は空でない ]: ◎ If controller.[[pendingPullIntos]] is not empty,
- %controller.[[pendingPullIntos]] の~~末尾に %pullIntoDescriptor を付加する ◎ Append pullIntoDescriptor as the last element of controller.[[pendingPullIntos]].
- ~RET ! `ReadableStreamAddReadIntoRequest$A( %stream, %forAuthorCode ) ◎ Return ! ReadableStreamAddReadIntoRequest(stream, forAuthorCode).
-
~IF[ %stream.[[state]] ~EQ `closed^l ]: ◎ If stream.[[state]] is "closed",
- %emptyView ~LET ! `Construct$A( %ctor, « %pullIntoDescriptor.[[buffer]], %pullIntoDescriptor.[[byteOffset]], `0^b » ) ◎ Let emptyView be ! Construct(ctor, « pullIntoDescriptor.[[buffer]], pullIntoDescriptor.[[byteOffset]], 0 »).
- ~RET ! `ReadableStreamCreateReadResult$A( %emptyView, ~true, %forAuthorCode ) で`解決される~promise$ ◎ Return a promise resolved with ! ReadableStreamCreateReadResult(emptyView, true, forAuthorCode).
-
~IF[ %controller.[[queueTotalSize]] ~GT `0^b ]: ◎ If controller.[[queueTotalSize]] > 0,
-
~IF[ ! `ReadableByteStreamControllerFillPullIntoDescriptorFromQueue$A( %controller, %pullIntoDescriptor ) ~EQ ~true ]: ◎ If ! ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) is true,
- %filledView ~LET ! `ReadableByteStreamControllerConvertPullIntoDescriptor$A( %pullIntoDescriptor ) ◎ Let filledView be ! ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
- ! `ReadableByteStreamControllerHandleQueueDrain$A( %controller ) ◎ Perform ! ReadableByteStreamControllerHandleQueueDrain(controller).
- ~RET ! `ReadableStreamCreateReadResult$A( %filledView, ~false, %forAuthorCode ) で`解決される~promise$ ◎ Return a promise resolved with ! ReadableStreamCreateReadResult(filledView, false, forAuthorCode).
-
~IF[ %controller.[[closeRequested]] ~EQ ~true ]: ◎ If controller.[[closeRequested]] is true,
- %e ~LET `TypeError^b 例外 ◎ Let e be a TypeError exception.
- ! `ReadableByteStreamControllerError$A( %controller, %e ) ◎ Perform ! ReadableByteStreamControllerError(controller, e).
- ~RET %e で`却下される~promise$ ◎ Return a promise rejected with e.
-
- %controller.[[pendingPullIntos]] の~~末尾に %pullIntoDescriptor を付加する ◎ Append pullIntoDescriptor as the last element of controller.[[pendingPullIntos]].
- %promise ~LET ! `ReadableStreamAddReadIntoRequest$A( %stream, %forAuthorCode ) ◎ Let promise be ! ReadableStreamAddReadIntoRequest(stream, forAuthorCode).
- ! `ReadableByteStreamControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
- ~RET %promise ◎ Return promise.
3.12.18. `ReadableByteStreamControllerRespond( controller, bytesWritten )^A
- %bytesWritten ~LET ? `ToNumber$A( %bytesWritten ) ◎ Let bytesWritten be ? ToNumber(bytesWritten).
- ~IF[ ! `IsFiniteNonNegativeNumber$A( %bytesWritten ) ~EQ ~false ] ⇒ ~THROW `RangeError^b ◎ If ! IsFiniteNonNegativeNumber(bytesWritten) is false, ◎ • Throw a RangeError exception.
- ~Assert: %controller.[[pendingPullIntos]] は空でない ◎ Assert: controller.[[pendingPullIntos]] is not empty.
- ? `ReadableByteStreamControllerRespondInternal$A( %controller, %bytesWritten ) ◎ Perform ? ReadableByteStreamControllerRespondInternal(controller, bytesWritten).
3.12.19. `ReadableByteStreamControllerRespondInClosedState( controller, firstDescriptor )^A
- %firstDescriptor.[[buffer]] ~SET ! `TransferArrayBuffer$A( %firstDescriptor.[[buffer]] ) ◎ Set firstDescriptor.[[buffer]] to ! TransferArrayBuffer(firstDescriptor.[[buffer]]).
- ~Assert: %firstDescriptor.[[bytesFilled]] ~EQ `0^b ◎ Assert: firstDescriptor.[[bytesFilled]] is 0.
- %stream ~LET %controller.[[controlledReadableByteStream]] ◎ Let stream be controller.[[controlledReadableByteStream]].
-
~IF[ ! `ReadableStreamHasBYOBReader$A( %stream ) ~EQ ~true ]: ◎ If ! ReadableStreamHasBYOBReader(stream) is true,
-
~WHILE ! `ReadableStreamGetNumReadIntoRequests$A( %stream ) ~GT `0^b : ◎ Repeat the following steps while ! ReadableStreamGetNumReadIntoRequests(stream) > 0,
- %pullIntoDescriptor ~LET ! `ReadableByteStreamControllerShiftPendingPullInto$A( %controller ) ◎ Let pullIntoDescriptor be ! ReadableByteStreamControllerShiftPendingPullInto(controller).
- ! `ReadableByteStreamControllerCommitPullIntoDescriptor$A( %stream, %pullIntoDescriptor) ◎ Perform ! ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor).
-
3.12.20. `ReadableByteStreamControllerRespondInReadableState( controller, bytesWritten, pullIntoDescriptor )^A
- ~IF[ ( %pullIntoDescriptor.[[bytesFilled]] + %bytesWritten ) ~GT %pullIntoDescriptor.[[byteLength]] ] ⇒ ~THROW `RangeError^b ◎ If pullIntoDescriptor.[[bytesFilled]] + bytesWritten > pullIntoDescriptor.[[byteLength]], throw a RangeError exception.
- ! `ReadableByteStreamControllerFillHeadPullIntoDescriptor$A( %controller, %bytesWritten, %pullIntoDescriptor ) ◎ Perform ! ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesWritten, pullIntoDescriptor).
- ~IF[ %pullIntoDescriptor.[[bytesFilled]] ~LT %pullIntoDescriptor.[[elementSize]] ] ⇒ ~RET ◎ If pullIntoDescriptor.[[bytesFilled]] < pullIntoDescriptor.[[elementSize]], return.
- ! `ReadableByteStreamControllerShiftPendingPullInto$A( %controller ) ◎ Perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).
- %remainderSize ~LET ( %pullIntoDescriptor.[[bytesFilled]] ~mod %pullIntoDescriptor.[[elementSize]] ) ◎ Let remainderSize be pullIntoDescriptor.[[bytesFilled]] mod pullIntoDescriptor.[[elementSize]].
-
~IF[ %remainderSize ~GT `0^b ]: ◎ If remainderSize > 0,
- %end ~LET ( %pullIntoDescriptor.[[byteOffset]] + %pullIntoDescriptor.[[bytesFilled]] ) ◎ Let end be pullIntoDescriptor.[[byteOffset]] + pullIntoDescriptor.[[bytesFilled]].
- %remainder ~LET ? `CloneArrayBuffer$A( %pullIntoDescriptor.[[buffer]], ( %end − %remainderSize ), %remainderSize, `~ArrayBuffer$ ) ◎ Let remainder be ? CloneArrayBuffer(pullIntoDescriptor.[[buffer]], end − remainderSize, remainderSize, %ArrayBuffer%).
- ! `ReadableByteStreamControllerEnqueueChunkToQueue$A( %controller, %remainder, `0^b, %remainder.[[ByteLength]] ) ◎ Perform ! ReadableByteStreamControllerEnqueueChunkToQueue(controller, remainder, 0, remainder.[[ByteLength]]).
- %pullIntoDescriptor.[[buffer]] ~SET ! `TransferArrayBuffer$A( %pullIntoDescriptor.[[buffer]] ) ◎ Set pullIntoDescriptor.[[buffer]] to ! TransferArrayBuffer(pullIntoDescriptor.[[buffer]]).
- %pullIntoDescriptor.[[bytesFilled]] ~SET %pullIntoDescriptor.[[bytesFilled]] − %remainderSize ◎ Set pullIntoDescriptor.[[bytesFilled]] to pullIntoDescriptor.[[bytesFilled]] − remainderSize.
- ! `ReadableByteStreamControllerCommitPullIntoDescriptor$A( %controller.[[controlledReadableByteStream]], %pullIntoDescriptor ) ◎ Perform ! ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[controlledReadableByteStream]], pullIntoDescriptor).
- ! `ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue$A( %controller ) ◎ Perform ! ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
3.12.21. `ReadableByteStreamControllerRespondInternal( controller, bytesWritten )^A
- %firstDescriptor ~LET %controller.[[pendingPullIntos]] の最初の要素 ◎ Let firstDescriptor be the first element of controller.[[pendingPullIntos]].
- %stream ~LET %controller.[[controlledReadableByteStream]] ◎ Let stream be controller.[[controlledReadableByteStream]].
-
~IF[ %stream.[[state]] ~EQ `closed^l ]: ◎ If stream.[[state]] is "closed",
- ~IF[ %bytesWritten ~NEQ `0^b ] ⇒ ~THROW `TypeError^b ◎ If bytesWritten is not 0, throw a TypeError exception.
- ! `ReadableByteStreamControllerRespondInClosedState$A( %controller, %firstDescriptor ) ◎ Perform ! ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor).
-
~ELSE: ◎ Otherwise,
- ~Assert: %stream.[[state]] ~EQ `readable^l ◎ Assert: stream.[[state]] is "readable".
- ? `ReadableByteStreamControllerRespondInReadableState$A( %controller, %bytesWritten, %firstDescriptor ) ◎ Perform ? ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, firstDescriptor).
- ! `ReadableByteStreamControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
3.12.22. `ReadableByteStreamControllerRespondWithNewView( controller, view )^A
- ~Assert: %controller.[[pendingPullIntos]] は空でない ◎ Assert: controller.[[pendingPullIntos]] is not empty.
- %firstDescriptor ~LET %controller.[[pendingPullIntos]] の最初の要素 ◎ Let firstDescriptor be the first element of controller.[[pendingPullIntos]].
- ~IF[ ( %firstDescriptor.[[byteOffset]] + %firstDescriptor.[[bytesFilled]] ) ~NEQ %view.[[ByteOffset]] ] ⇒ ~THROW `RangeError^b ◎ If firstDescriptor.[[byteOffset]] + firstDescriptor.[[bytesFilled]] is not view.[[ByteOffset]], throw a RangeError exception.
- ~IF[ %firstDescriptor.[[byteLength]] ~NEQ %view.[[ByteLength]] ] ⇒ ~THROW `RangeError^b ◎ If firstDescriptor.[[byteLength]] is not view.[[ByteLength]], throw a RangeError exception.
- %firstDescriptor.[[buffer]] ~SET %view.[[ViewedArrayBuffer]] ◎ Set firstDescriptor.[[buffer]] to view.[[ViewedArrayBuffer]].
- ? `ReadableByteStreamControllerRespondInternal$A( %controller, %view.[[ByteLength]] ) ◎ Perform ? ReadableByteStreamControllerRespondInternal(controller, view.[[ByteLength]]).
3.12.23. `ReadableByteStreamControllerShiftPendingPullInto( controller )^A
- %descriptor ~LET %controller.[[pendingPullIntos]] の最初の要素 ◎ Let descriptor be the first element of controller.[[pendingPullIntos]].
- %controller.[[pendingPullIntos]] から %descriptor を除去する — 後続の要素たちは~~先頭へ一つずらす ◎ Remove descriptor from controller.[[pendingPullIntos]], shifting all other elements downward (so that the second becomes the first, and so on).
- ! `ReadableByteStreamControllerInvalidateBYOBRequest$A( %controller ) ◎ Perform ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).
- ~RET %descriptor ◎ Return descriptor.
3.12.24. `ReadableByteStreamControllerShouldCallPull( controller )^A
- %stream ~LET %controller.[[controlledReadableByteStream]] ◎ Let stream be controller.[[controlledReadableByteStream]].
- ~IF[ %stream.[[state]] ~NEQ `readable^l ] ⇒ ~RET ~false ◎ If stream.[[state]] is not "readable", return false.
- ~IF[ %controller.[[closeRequested]] ~EQ ~true ] ⇒ ~RET ~false ◎ If controller.[[closeRequested]] is true, return false.
- ~IF[ %controller.[[started]] ~EQ ~false ] ⇒ ~RET ~false ◎ If controller.[[started]] is false, return false.
- ~IF[ ! `ReadableStreamHasDefaultReader$A( %stream ) ~EQ ~true ]~AND[ ! `ReadableStreamGetNumReadRequests$A( %stream ) ~GT `0^b ] ⇒ ~RET ~true ◎ If ! ReadableStreamHasDefaultReader(stream) is true and ! ReadableStreamGetNumReadRequests(stream) > 0, return true.
- ~IF[ ! `ReadableStreamHasBYOBReader$A( %stream ) ~EQ ~true ]~AND[ ! `ReadableStreamGetNumReadIntoRequests$A( %stream ) ~GT `0^b ] ⇒ ~RET ~true ◎ If ! ReadableStreamHasBYOBReader(stream) is true and ! ReadableStreamGetNumReadIntoRequests(stream) > 0, return true.
- %desiredSize ~LET ! `ReadableByteStreamControllerGetDesiredSize$A( %controller ) ◎ Let desiredSize be ! ReadableByteStreamControllerGetDesiredSize(controller).
- ~Assert: %desiredSize ~NEQ `null^b ◎ Assert: desiredSize is not null.
- ~IF[ %desiredSize ~GT `0^b ] ⇒ ~RET ~true ◎ If desiredSize > 0, return true.
- ~RET ~false ◎ Return false.
3.12.25. `SetUpReadableByteStreamController( stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, autoAllocateChunkSize )^A
- ~Assert: %stream.[[readableStreamController]] ~EQ ~undefined ◎ Assert: stream.[[readableStreamController]] is undefined.
-
~IF[ %autoAllocateChunkSize ~NEQ ~undefined ]: ◎ If autoAllocateChunkSize is not undefined,
- ~Assert: ! `IsInteger$A( %autoAllocateChunkSize ) ~EQ ~true ◎ Assert: ! IsInteger(autoAllocateChunkSize) is true.
- ~Assert: %autoAllocateChunkSize ~GT 0 ◎ Assert: autoAllocateChunkSize is positive.
- %controller の ⇒# .[[controlledReadableByteStream]] ~SET %stream .[[pullAgain]] ~SET ~false, .[[pulling]] ~SET ~false ◎ Set controller.[[controlledReadableByteStream]] to stream. ◎ Set controller.[[pullAgain]] and controller.[[pulling]] to false.
- ! `ReadableByteStreamControllerClearPendingPullIntos$A( %controller ) ◎ Perform ! ReadableByteStreamControllerClearPendingPullIntos(controller).
- ! `ResetQueue$A( %controller ) ◎ Perform ! ResetQueue(controller).
- %controller の ⇒# .[[closeRequested]] ~SET ~false, .[[started]] ~SET ~false .[[strategyHWM]] ~SET ? `ValidateAndNormalizeHighWaterMark$A( %highWaterMark ), .[[pullAlgorithm]] ~SET %pullAlgorithm, .[[cancelAlgorithm]] ~SET %cancelAlgorithm, .[[autoAllocateChunkSize]] ~SET %autoAllocateChunkSize, .[[pendingPullIntos]] ~SET 新たな空`~List$ ◎ Set controller.[[closeRequested]] and controller.[[started]] to false. ◎ Set controller.[[strategyHWM]] to ? ValidateAndNormalizeHighWaterMark(highWaterMark). ◎ Set controller.[[pullAlgorithm]] to pullAlgorithm. ◎ Set controller.[[cancelAlgorithm]] to cancelAlgorithm. ◎ Set controller.[[autoAllocateChunkSize]] to autoAllocateChunkSize. ◎ Set controller.[[pendingPullIntos]] to a new empty List.
- %stream.[[readableStreamController]] ~SET %controller ◎ Set stream.[[readableStreamController]] to controller.
- %startResult ~LET 次を遂行した結果 ⇒ %startAlgorithm() ◎ Let startResult be the result of performing startAlgorithm.
-
%startPromise ~LET %startResult で`解決される~promise$ ◎ Let startPromise be a promise resolved with startResult.
-
%startPromise の`充足-時$には: ◎ Upon fulfillment of startPromise,
- %controller.[[started]] ~SET ~true ◎ Set controller.[[started]] to true.
- ~Assert: %controller.[[pulling]] ~EQ ~false ◎ Assert: controller.[[pulling]] is false.
- ~Assert: %controller.[[pullAgain]] ~EQ ~false ◎ Assert: controller.[[pullAgain]] is false.
- ! `ReadableByteStreamControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
-
事由 %r による %startPromise の`却下-時$には: ◎ Upon rejection of startPromise with reason r,
- ! `ReadableByteStreamControllerError$A( %controller, %r ) ◎ Perform ! ReadableByteStreamControllerError(controller, r).
-
3.12.26. `SetUpReadableByteStreamControllerFromUnderlyingSource( stream, underlyingByteSource, highWaterMark )^A
- ~Assert: %underlyingByteSource ~NEQ ~undefined ◎ Assert: underlyingByteSource is not undefined.
- %controller ~LET `ObjectCreate$A( `ReadableByteStreamController$C の `prototype^c ~propの元の値 ) ◎ Let controller be ObjectCreate(the original value of ReadableByteStreamController's prototype property).
-
%startAlgorithm ~LET 次を走らす手続き: ◎ Let startAlgorithm be the following steps:
- ~RET ? `InvokeOrNoop$A( %underlyingByteSource, `start^l, « %controller » ) ◎ Return ? InvokeOrNoop(underlyingByteSource, "start", « controller »).
- %pullAlgorithm ~LET ? `CreateAlgorithmFromUnderlyingMethod$A( %underlyingByteSource, `pull^l, `0^b, « %controller » ) ◎ Let pullAlgorithm be ? CreateAlgorithmFromUnderlyingMethod(underlyingByteSource, "pull", 0, « controller »).
- %cancelAlgorithm ~LET ? `CreateAlgorithmFromUnderlyingMethod$A( %underlyingByteSource, `cancel^l, `1^b, « » ) ◎ Let cancelAlgorithm be ? CreateAlgorithmFromUnderlyingMethod(underlyingByteSource, "cancel", 1, « »).
- %autoAllocateChunkSize ~LET ? `GetV$A( %underlyingByteSource, `autoAllocateChunkSize^l ) ◎ Let autoAllocateChunkSize be ? GetV(underlyingByteSource, "autoAllocateChunkSize").
-
~IF[ %autoAllocateChunkSize ~NEQ ~undefined ]: ◎ If autoAllocateChunkSize is not undefined,
- %autoAllocateChunkSize ~SET ? `ToNumber$A( %autoAllocateChunkSize ) ◎ Set autoAllocateChunkSize to ? ToNumber(autoAllocateChunkSize).
- ~IF[ ! `IsInteger$A( %autoAllocateChunkSize ) ~EQ ~false ]~OR[ %autoAllocateChunkSize ~LTE `0^b ] ⇒ ~THROW `RangeError^b ◎ If ! IsInteger(autoAllocateChunkSize) is false, or if autoAllocateChunkSize ≤ 0, throw a RangeError exception.
- ? `SetUpReadableByteStreamController$A( %stream, %controller, %startAlgorithm, %pullAlgorithm, %cancelAlgorithm, %highWaterMark, %autoAllocateChunkSize ) ◎ Perform ? SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, autoAllocateChunkSize).
3.12.27. `SetUpReadableStreamBYOBRequest(request, controller, view )^A
- ~Assert: ! `IsReadableByteStreamController$A( %controller ) ~EQ ~true ◎ Assert: ! IsReadableByteStreamController(controller) is true.
- ~Assert: `Type$A( %view ) ~EQ `Object^b ◎ Assert: Type(view) is Object.
- ~Assert: %view は [[ViewedArrayBuffer]] 内部~slotを持つ ◎ Assert: view has a [[ViewedArrayBuffer]] internal slot.
- ~Assert: ! `IsDetachedBuffer$A( %view.[[ViewedArrayBuffer]] ) ~EQ ~false ◎ Assert: ! IsDetachedBuffer(view.[[ViewedArrayBuffer]]) is false.
- %request.[[associatedReadableByteStreamController]] ~SET %controller ◎ Set request.[[associatedReadableByteStreamController]] to controller.
- %request.[[view]] ~SET %view ◎ Set request.[[view]] to view.
4. 可書~stream
4.1. 可書~streamの用法
`可読~stream$へ書込する通例的な仕方は、単純に,可読~streamをそれに`~pipeする$ことである。 これにより、その`背圧$が尊重されるようになる — 可書~streamの`下層~槽$が,可読~streamが生産できるほど高速に~dataを受容できない場合に、可読~streamにその旨が伝わり,その~data生産を減速させる機会を得られるようになる。 ◎ The usual way to write to a writable stream is to simply pipe a readable stream to it. This ensures that backpressure is respected, so that if the writable stream’s underlying sink is not able to accept data as fast as the readable stream can produce it, the readable stream is informed of this and has a chance to slow down its data production.
readableStream.pipeTo(%writableStream) .then(() => console.log(`すべての~dataは成功裡に書込されました^l)) .catch(%e => console.error(`何かまずいことが起きたようです^l, %e));
`書込器$を獲得して,その `write()$dw / `close()$dw ~methodを利用すれば、可書~streamに直に書込することもできる。 それらは、[ 流入~書込を,~queueした上で`下層~槽$へ順に回送する ]ことを,内部的に手入れするので、手間をかけず無差別的に,可書~streamへ書込できる: ◎ You can also write directly to writable streams by acquiring a writer and using its write() and close() methods. Since writable streams queue any incoming writes, and take care internally to forward them to the underlying sink in sequence, you can indiscriminately write to a writable stream without much ceremony:
function writeArrayToStream(%array, %writableStream) { const %writer = %writableStream.getWriter(); %array.forEach(%chunk => %writer.write(%chunk).catch(() => {})); return %writer.close(); } writeArrayToStream([1, 2, 3, 4, 5], %writableStream) .then(() => console.log(`すべて終えました^l)) .catch(%e => console.error(`~streamに~errorが生じました: ^l + %e));
`.catch(() => {})^c を利用して, `write()$dw ~methodからの却下を抑止していることに注意 — 致命的~errorは, `close()$dw ~methodの却下を介して通知されることになり、~catchせずに放った場合[ `unhandledrejection$et ~event / ~consoleに警告 ]を生じさせ得る。 ◎ Note how we use .catch(() => {}) to suppress any rejections from the write() method; we’ll be notified of any fatal errors via a rejection of the close() method, and leaving them un-caught would cause potential unhandledrejection events and console warnings.
これまでの例では、書込器( %writer )の `close()$dw ~methodから返された~promiseを見ることで,~stream全体の成否についてのみに注目していた。 その~promiseは、~streamにて — その初期化-時, それへの書込み時, その~close時にて — 何らかの不具合が生じたときに却下されることになり、また,~streamが成功裡に~closeされたなら 充足されることになる。 多くの場合、これについて~careしておけば済む。 ◎ In the previous example we only paid attention to the success or failure of the entire stream, by looking at the promise returned by the writer’s close() method. That promise will reject if anything goes wrong with the stream—initializing it, writing to it, or closing it. And it will fulfill once the stream is successfully closed. Often this is all you care about.
が、特定の`~chunk$に対し,書込みの成功について~careする場合は、書込器の `write()$dw ~methodから返される~promiseを利用できる: ◎ However, if you care about the success of writing a specific chunk, you can use the promise returned by the writer’s write() method:
%writer.write(`~data内のある~chunk^l) .then(() => console.log(`~chunkは成功裡に書込されました^l)) .catch(%e => console.error(%e));
“成功” が何を意味するかは、所与の~stream~instance(より精確には, その`下層~槽$)が決める。 例えば,~file~streamに対してなら、単純に OS が書込を受容したことを意味し,`~chunk$を~diskへ書出すことは必要とされないであろう。 そのような合図を与える~~能が全くない~streamもあるかもしれない — その事例では、返される~promiseは即時に充足されることになる。 ◎ What "success" means is up to a given stream instance (or more precisely, its underlying sink) to decide. For example, for a file stream it could simply mean that the OS has accepted the write, and not necessarily that the chunk has been flushed to disk. Some streams might not be able to give such a signal at all, in which case the returned promise will fulfill immediately.
`書込器$の[ `desiredSize$dw, `ready$dw ]~propにより、`生産器$は,~streamからの流れ制御の合図に より精確に応答して,記憶域の使用量を ~streamに指定された`限界水位$より下に保ち続けれるようになる。 次の例は、無限に続く~randomな~byte列を~streamに書込する — その際に、 `desiredSize$dw を利用して,所与の時点に何~byte生成するかを決定し、 `ready$dw を利用して,`背圧$が収まるまで待機する。 ◎ The desiredSize and ready properties of writable stream writers allow producers to more precisely respond to flow control signals from the stream, to keep memory usage below the stream’s specified high water mark. The following example writes an infinite sequence of random bytes to a stream, using desiredSize to determine how many bytes to generate at a given time, and using ready to wait for the backpressure to subside.
async function writeRandomBytesForever(%writableStream) {
const %writer = %writableStream.getWriter();
while (true) {
await %writer.ready;
const %bytes = new Uint8Array(%writer.desiredSize);
crypto.getRandomValues(%bytes);
/*
次では、目的をもって `await^c しない
— %writer.`ready^c を `await^c するので十分なので。
◎
Purposefully don’t await; awaiting writer.ready is enough.
*/
%writer.write(%bytes).catch(() => {});
}
}
writeRandomBytesForever(myWritableStream).catch(
e => console.error(`何か不具合が生じたようです^l, e)
);
`write()$dw から返される~promiseを `await^c していないことに注意 — それは、 `ready$dw ~promiseを `await^c するのと~~重複するので。 加えて,以前の例と同様に、 `write()$dw から返される~promiseに対しては, `.catch(() => {})^c ~patternも利用している — この事例では、どの失敗も `ready$dw ~promiseを `await^c するときに通知されるので。 ◎ Note how we don’t await the promise returned by write(); this would be redundant with awaiting the ready promise. Additionally, similar to a previous example, we use the .catch(() => {}) pattern on the promises returned by write(); in this case we’ll be notified about any failures awaiting the ready promise.
`write()$dw から返される~promiseを `await^c するのが,どうして不良な案になるのか、もっとはっきりさせるため,上の例の改変を考える — そこでも、 `WritableStreamDefaultWriter$C ~interfaceは直に利用し続けるが,所与の時点で書込する~byte数は制御しない。 その事例でも、`背圧$を尊重している~codeは同じようになる: ◎ To further emphasize how it’s a bad idea to await the promise returned by write(), consider a modification of the above example, where we continue to use the WritableStreamDefaultWriter interface directly, but we don’t control how many bytes we have to write at a given time. In that case, the backpressure-respecting code looks the same:
async function writeSuppliedBytesForever(%writableStream, %getBytes) { const %writer = %writableStream.getWriter(); while (true) { await %writer.ready; const %bytes = %getBytes(); %writer.write(%bytes).catch(() => {}); } }
以前の例では、毎回~常に,正確に %writer.`desiredSize$dw 個の~byteを書込していたので,[ `write()$dw が返す~promise, `ready$dw ~promise ]は同期していたが、この事例では、前者の前に後者の~promiseが充足されることも,ごく~~普通にあり得る。 `ready$dw ~promiseは、[ `~streamの内部~queueの残り~size$ ~GT 0 ]になったとき,充足されることに注意 — それは,書込が成功する前になるかもしれない(とりわけ、`限界水位$が高い事例では)。 ◎ Unlike the previous example, where—because we were always writing exactly writer.desiredSize bytes each time—the write() and ready promises were synchronized, in this case it’s quite possible that the ready promise fulfills before the one returned by write() does. Remember, the ready promise fulfills when the desired size becomes positive, which might be before the write succeeds (especially in cases with a larger high water mark).
言い換えれば、 `write()$dw の返値を `await^c することは、[ ~streamの`内部~queue$内には,書込は決して~queue-upされない代わりに、以前の書込が成功した後に限り,書込を実行する ]ことを意味する — その結果、時間あたりの流量は低下し得る。 ◎ In other words, awaiting the return value of write() means you never queue up writes in the stream’s internal queue, instead only executing a write after the previous one succeeds, which can result in low throughput.
4.2. `WritableStream^C ~class
4.2.1. ~class定義
~INFORMATIVE`WritableStream$C ~classは、 `ECMASCRIPT$r 風の構文で書くならば,次のようになる: ◎ If one were to write the WritableStream class in something close to the syntax of [ECMASCRIPT], it would look like
class WritableStream { `constructor$ws(%underlyingSink = {}, %strategy = {}) get `locked()$ws `abort(reason)$ws `getWriter()$ws }
4.2.2. 各種 内部~slot
`WritableStream$C の各~instanceは、次の一覧に述べる各種 内部~slotを伴って作成される: ◎ Instances of WritableStream are created with the internal slots described in the following table:
内部~slot | 説明0(参考) |
---|---|
[[backpressure]] | 制御器により設定される~背圧~合図 ◎ The backpressure signal set by the controller |
[[closeRequest]] | 書込器の `close()$dw ~methodから~返される~promise ◎ The promise returned from the writer close() method |
[[inFlightWriteRequest]] | この~slotは、`下層~槽$の書込~algoが まだ実行-中で充足されていない間に,現在の~in-flight 【“~~処理中にある”】書込~演算~用の~promiseに設定される。 これは、再入~callを防止するために利用される。 ◎ A slot set to the promise for the current in-flight write operation while the underlying sink’s write algorithm is executing and has not yet fulfilled, used to prevent reentrant calls |
[[inFlightCloseRequest]] | この~slotは、`下層~槽$の `close()^m ~methodが まだ~実行-中で~充足されていない間に,現在の~in-flight~close~algo用の~promiseに設定される。 これは、 `abort()$dw ~methodにより~closeが中断されるのを防止するために利用される。 ◎ A slot set to the promise for the current in-flight close operation while the underlying sink’s close algorithm is executing and has not yet fulfilled, used to prevent the abort() method from interrupting close |
[[pendingAbortRequest]] | [ `abort()$dw から返される~promise, `abort()$dw に渡した %reason ]を包含している`~Record$ ◎ A Record containing the promise returned from abort() and the reason passed to abort() |
[[state]] | 内部に利用される ~streamの現在の状態を包含している文字列 — 次のいずれか: `writable^l, `closed^l, `erroring^l, `errored^l ◎ A string containing the stream’s current state, used internally; one of "writable", "closed", "erroring", or "errored" |
[[storedError]] | ~streamが どのように失敗したかを指示する値 — [ `errored^l 状態にある~stream上に演算しようと試行している ]ときに、失敗~事由か例外として与えられることになる。 ◎ A value indicating how the stream failed, to be given as a failure reason or exception when trying to operate on the stream while in the "errored" state |
[[writableStreamController]] | [ この~streamの状態と~queueを制御する能 ]を伴って作成される `WritableStreamDefaultController$C 。 `IsWritableStream$A による~brand検査-時にも利用される。 ◎ A WritableStreamDefaultController created with the ability to control the state and queue of this stream; also used for the IsWritableStream brand check |
[[writer]] | ~streamが書込器に`~lockされて$[ いるならば `WritableStreamDefaultWriter$C の~instance / いなければ ~undefined ]。 ◎ A WritableStreamDefaultWriter instance, if the stream is locked to a writer, or undefined if it is not |
[[writeRequests]] | 一連の[ `下層~槽$がまだ処理していない書込~要請に対する~promise ]からなる,~streamの内部~queueを表現する`~List$。 ◎ A List of promises representing the stream’s internal queue of write requests not yet processed by the underlying sink |
注記: [[inFlightCloseRequest]] ~slot, [[closeRequest]] ~slotは、互いに排他的である。 また、[ [[inFlightWriteRequest]] ~NEQ ~undefined ]の間に [[writeRequests]] から要素が除去されることはない。 実装は、これらの不変則に基づいて これらの~slot用の~storageを最適化できる。 ◎ The [[inFlightCloseRequest]] slot and [[closeRequest]] slot are mutually exclusive. Similarly, no element will be removed from [[writeRequests]] while [[inFlightWriteRequest]] is not undefined. Implementations can optimize storage for these slots based on these invariants.
4.2.3. `new WritableStream( underlyingSink = {}, strategy = {} )^m
%underlyingSink 引数は — `§下層~槽~API$にて述べるように — `下層~槽$を表現する。 ◎ The underlyingSink argument represents the underlying sink, as described in §4.2.4 Underlying sink API.
%strategy 引数は — `§~queuing策~API$にて述べるように — ~streamの`~queuing策$を表現する。 供されなかった場合の既定の挙動は、`限界水位$ 1 にされた `CountQueuingStrategy$C と同じになる。 ◎ The strategy argument represents the stream’s queuing strategy, as described in §6.1.1 The queuing strategy API. If it is not provided, the default behavior will be the same as a CountQueuingStrategy with a high water mark of 1.
- ! `InitializeWritableStream$A( ~this ) ◎ Perform ! InitializeWritableStream(this).
- %size ~LET ? `GetV$A( %strategy, `size^l ) ◎ Let size be ? GetV(strategy, "size").
- %highWaterMark ~LET ? `GetV$A( %strategy, `highWaterMark^l ) ◎ Let highWaterMark be ? GetV(strategy, "highWaterMark").
- %type ~LET ? `GetV$A( %underlyingSink, `type^l ) ◎ Let type be ? GetV(underlyingSink, "type").
-
~IF[ %type ~NEQ ~undefined ] ⇒ ~THROW `RangeError^b ◎ If type is not undefined, throw a RangeError exception.
これは、後方互換性を懸念することなく,将来に新たな型を追加できるようにする。 ◎ This is to allow us to add new potential types in the future, without backward-compatibility concerns.
- %sizeAlgorithm ~LET ? `MakeSizeAlgorithmFromSizeFunction$A( %size ) ◎ Let sizeAlgorithm be ? MakeSizeAlgorithmFromSizeFunction(size).
- ~IF[ %highWaterMark ~EQ ~undefined ] ⇒ %highWaterMark ~SET `1^b ◎ If highWaterMark is undefined, let highWaterMark be 1.
- %highWaterMark ~SET ? `ValidateAndNormalizeHighWaterMark$A( %highWaterMark ) ◎ Set highWaterMark to ? ValidateAndNormalizeHighWaterMark(highWaterMark).
- ? `SetUpWritableStreamDefaultControllerFromUnderlyingSink$A( ~this, %underlyingSink, %highWaterMark, %sizeAlgorithm ) ◎ Perform ? SetUpWritableStreamDefaultControllerFromUnderlyingSink(this, underlyingSink, highWaterMark, sizeAlgorithm).
4.2.4. 下層~槽~API
~INFORMATIVE`WritableStream()$ws 構築子は、 1 個目の引数に[ `下層~槽$を表現している~JS~obj ]を受容する。 そのような~objには、次に挙げる~propを包含させられる: ◎ The WritableStream() constructor accepts as its first argument a JavaScript object representing the underlying sink. Such objects can contain any of the following properties:
- `start(controller)@snk
- この関数は、 `WritableStream$C を作成する間に即時に~callされる。 ◎ A function that is called immediately during creation of the WritableStream.
- これは概して、資源が表現されている`下層~槽$への~accessを獲得するために利用される。 ◎ Typically this is used to acquire access to the underlying sink resource being represented.
- ここで何かを設定しておく処理が非同期的になる場合、この関数は,成否を合図する~promiseを返すようにすることもできる — 却下される~promiseは、~streamを~errorにすることになる。 投出された例外は、 `WritableStream()$ws 構築子により再~投出されることになる。 ◎ If this setup process is asynchronous, it can return a promise to signal success or failure; a rejected promise will error the stream. Any thrown exceptions will be re-thrown by the WritableStream() constructor.
- `write(chunk, controller)@snk
- この関数は、[ `下層~槽$へ書込される~dataを成す,新たな`~chunk$ ]が準備済みになったときに~callされる。 ~stream実装は、この関数が~callされるのは、以前の書込が成功した後に限られ, かつ[ `start()$snk が成功する前 /[ `close()$snk / `abort()$snk ]~callされた後には決してならないことを保証する。 ◎ A function that is called when a new chunk of data is ready to be written to the underlying sink. The stream implementation guarantees that this function will be called only after previous writes have succeeded, and never before start() has succeeded or after close() or abort() have been called.
- この関数は、`下層~槽$により提示される資源に,実際に~dataを — 例えば,より低levelな~APIを~callして — 送信するために利用される。 ◎ This function is used to actually send the data to the resource presented by the underlying sink, for example by calling a lower-level API.
- ~dataを書込する処理が非同期的になる場合、この関数は — ~API利用者に成否~合図を通信するために — 成否を合図する~promiseを返すようにすることもできる。 この~promiseの返値は、 %writer.`write()$dw の~call元が個々の書込を監視できるよう,~call元へ通信されることになる。 例外を投出した場合、却下される~promiseを返すのと同じに扱われる。 ◎ If the process of writing data is asynchronous, and communicates success or failure signals back to its user, then this function can return a promise to signal success or failure. This promise return value will be communicated back to the caller of writer.write(), so they can monitor that individual write. Throwing an exception is treated the same as returning a rejected promise.
- そのような合図は、常に可用になるとは限らないことに注意。 そのような事例では、何も返さないのが最善になる — 次の 2 つを比較されたし ⇒# `§背圧や成功の合図を伴わない可書~stream$, `§背圧や成功の合図を伴う可書~stream$ ◎ Note that such signals are not always available; compare e.g. §8.6 A writable stream with no backpressure or success signals with §8.7 A writable stream with backpressure and success signals. In such cases, it’s best to not return anything.
- この関数が返す~promiseは、[ `~streamの内部~queueの残り~size$を算出する目的 ]において,[ 所与の~chunkを,書込されるに伴い数えるかどうか ]も統治し得る。 すなわち、[ %writer . `desiredSize$dw は、~promiseが決着するまでの間は,以前の値であり続け],[ もっと~chunkを欲することを合図するために増やされるのは,書込が成功した場合に限られる ]ことになる。 ◎ The promise potentially returned by this function also governs whether the given chunk counts as written for the purposes of computed the desired size to fill the stream’s internal queue. That is, during the time it takes the promise to settle, writer.desiredSize will stay at its previous value, only increasing to signal the desire for more chunks once the write succeeds.
- `close()@snk
- この関数は、`生産器$が[ 自身による,一連の`~chunk$の~streamへの書込みを終え,後続して~queue-upされたすべての書込が成功裡に完了した ]ことを — %writer.`close()$dw を介して — 合図した後に~callされる。 ◎ A function that is called after the producer signals, via writer.close(), that they are done writing chunks to the stream, and subsequently all queued-up writes have successfully completed.
- [ `下層~槽$への書込を[ 完結する/書出す ]/ 保持されている資源への~accessを解放する ]ために必要とされる動作があれば、この関数~内で遂行できる。 ◎ This function can perform any actions necessary to finalize or flush writes to the underlying sink, and release access to any held resources.
- この~shutdown処理が非同期的になる場合、この関数は,成否を合図する~promiseを返すようにすることもできる: その結果は,~callされた %writer.`close()$dw ~methodの返値を介して通信されることになる。 加えて、却下される~promiseは,~streamを — そのまま成功裡に~closeさせずに — ~errorにすることになる。 例外を投出した場合、却下される~promiseを返すのと同じに扱われる。 ◎ If the shutdown process is asynchronous, the function can return a promise to signal success or failure; the result will be communicated via the return value of the called writer.close() method. Additionally, a rejected promise will error the stream, instead of letting it close successfully. Throwing an exception is treated the same as returning a rejected promise.
- `abort(reason)@snk
- この関数は、`生産器$が[ ~streamを`中止-$したいと望む ]ことを — [ %stream.`abort()$ws / %writer.`abort()$dw ]を介して — 合図した後に~callされる。 その引数は、生産器がそれらの~methodに渡したのと同じ値をとる。 ◎ A function that is called after the producer signals, via stream.abort() or writer.abort(), that they wish to abort the stream. It takes as its argument the same value as was passed to those methods by the producer.
- 加えて,可書~streamは、`~pipeする$間に,一定の条件~下で中止されることもある — 詳細は、 `pipeTo()$rs ~methodの定義を見よ。 ◎ Writable streams can additionally be aborted under certain conditions during piping; see the definition of the pipeTo() method for more details.
- この関数は、保持されている資源があれば — `close()$snk とほぼ同様に — 片付けれるが、おそらく 何か~customな取扱いも伴われる。 ◎ This function can clean up any held resources, much like close(), but perhaps with some custom handling.
- この~shutdown処理が非同期的になる場合、この関数は,成否を合図する~promiseを返すようにすることもできる — その結果は、~callした `abort()^c ~methodの返値を介して通信されることになる。 例外を投出した場合、却下される~promiseを返すのと同じに扱われる。 いずれにせよ、~streamは — 中止されたことを指示する,新たな `TypeError$b で — ~errorにされることになる。 ◎ If the shutdown process is asynchronous, the function can return a promise to signal success or failure; the result will be communicated via the return value of the called abort() method. Throwing an exception is treated the same as returning a rejected promise. Regardless, the stream will be errored with a new TypeError indicating that it was aborted.
[ `start()$snk / `write()$snk ]に渡される %controller 引数は、 `WritableStreamDefaultController$C の~instanceであり,~streamを~errorにする能を備える。 これは主に、~promiseに基づかない~APIと橋渡しするために利用される。 その例は、`§背圧や成功の合図を伴わない可書~stream$に見れる。 ◎ The controller argument passed to start() and write() is an instance of WritableStreamDefaultController, and has the ability to error the stream. This is mainly used for bridging the gap with non-promise-based APIs, as seen for example in §8.6 A writable stream with no backpressure or success signals.
4.2.5. `WritableStream^C ~prototypeの各種~prop
4.2.5.1. `get locked^ws
`locked^ws 取得子は、 可書~streamが書込器に`~lockされて$いるかどうかを返す。 ◎ The locked getter returns whether or not the writable stream is locked to a writer.
- ~IF[ ! `IsWritableStream$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsWritableStream(this) is false, throw a TypeError exception.
- ~RET ! `IsWritableStreamLocked$A( ~this ) ◎ Return ! IsWritableStreamLocked(this).
4.2.5.2. `abort( reason )^ws
`abort()^m ~methodは、~streamを`中止-$する。 それは、生産器は最早~成功裡に~streamに書込できないことを合図する — 書込が~queue-upされたときは、破棄した上で,即時に~error状態に移行することになる。 これはまた、`下層~槽$の中止する仕組みも実行することになる。 ◎ The abort method aborts the stream, signaling that the producer can no longer successfully write to the stream and it is to be immediately moved to an errored state, with any queued-up writes discarded. This will also execute any abort mechanism of the underlying sink.
- ~IF[ ! `IsWritableStream$A( ~this ) ~EQ ~false ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsWritableStream(this) is false, return a promise rejected with a TypeError exception.
- ~IF[ ! `IsWritableStreamLocked$A( ~this ) ~EQ ~true ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
- ~RET ! `WritableStreamAbort$A( ~this, %reason ) ◎ Return ! WritableStreamAbort(this, reason).
4.2.5.3. `getWriter()^ws
`getWriter()^ws ~methodは、`書込器$( `WritableStreamDefaultWriter$C の~instance)を作成して,~streamをこの新たな書込器に`~lock$する。 ~streamが~lockされている間は、他の書込器は,この~lockが`解放-$されるまで獲得できない。 ◎ The getWriter method creates a writer (an instance of WritableStreamDefaultWriter) and locks the stream to the new writer. While the stream is locked, no other writer can be acquired until this one is released.
この機能性は、[ 他から中断されたり書込が差挟まれることなく~streamに書込する能を欲するような,抽象化 ]を創出するときに,とりわけ有用になる。 ~stream用の書込器を取得することにより,[ 他から同時に書込されて,書込した~dataが予測-不能になり,役立たずになる ]ことはないことを確保できる。 ◎ This functionality is especially useful for creating abstractions that desire the ability to write to a stream without interruption or interleaving. By getting a writer for the stream, you can ensure nobody else can write at the same time, which would cause the resulting written data to be unpredictable and probably useless.
- ~IF[ ! `IsWritableStream$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsWritableStream(this) is false, throw a TypeError exception.
- ~RET ? `AcquireWritableStreamDefaultWriter$A( ~this ) ◎ Return ? AcquireWritableStreamDefaultWriter(this).
4.3. 一般の可書~stream抽象~演算
以下の抽象~演算は、この仕様を成す大部分と違って,他の仕様からも 一般に有用になるよう意味されている — 単に,この仕様の各種~classの実装の一部としてではなく。 ◎ The following abstract operations, unlike most in this specification, are meant to be generally useful by other specifications, instead of just being part of the implementation of this spec’s classes.
4.3.1. `AcquireWritableStreamDefaultWriter( stream )^A
- ~RET ? `Construct$A( `WritableStreamDefaultWriter$C, %stream ) ◎ Return ? Construct(WritableStreamDefaultWriter, « stream »).
4.3.2. `CreateWritableStream( startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm [, highWaterMark [, sizeAlgorithm ] ] )^A
この抽象~演算は、 `WritableStream$C ~instanceを作成したいと望むような,他の仕様から~callされる用途に意味されている。
- [ %writeAlgorithm / %closeAlgorithm / %abortAlgorithm ]は、~promiseを返す~algoで~MUST。
- %sizeAlgorithm は、給されるならば,`~chunk$~objを受容して ~numberを返す~algoで~MUST。
- %highWaterMark は、給されるならば,負でも `NaN^b でもない ~numberで~MUST。
注記: `CreateWritableStream$A は、給された %startAlgorithm が投出するとき, そのときに限り例外を投出する。 ◎ CreateWritableStream throws an exception if and only if the supplied startAlgorithm throws.
- ~IF[ %highWaterMark は渡されていない ] ⇒ %highWaterMark ~SET `1^b ◎ If highWaterMark was not passed, set it to 1.
- ~IF[ %sizeAlgorithm は渡されていない ] ⇒ %sizeAlgorithm ~SET `1^b を返す~algo ◎ If sizeAlgorithm was not passed, set it to an algorithm that returns 1.
- ~Assert: ! `IsNonNegativeNumber$A( %highWaterMark ) ~EQ ~true ◎ Assert: ! IsNonNegativeNumber(highWaterMark) is true.
- %stream ~LET `ObjectCreate$A( `WritableStream$C の `prototype^c ~propの元の値 ) ◎ Let stream be ObjectCreate(the original value of WritableStream's prototype property).
- ! `InitializeWritableStream$A( %stream ) ◎ Perform ! InitializeWritableStream(stream).
- %controller ~LET `ObjectCreate$A( `WritableStreamDefaultController$C の `prototype^c ~propの元の値 ) ◎ Let controller be ObjectCreate(the original value of WritableStreamDefaultController's prototype property).
- ? `SetUpWritableStreamDefaultController$A( %stream, %controller, %startAlgorithm, %writeAlgorithm, %closeAlgorithm, %abortAlgorithm, %highWaterMark, %sizeAlgorithm ) ◎ Perform ? SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm).
- ~RET %stream ◎ Return stream.
4.3.3. `InitializeWritableStream( stream )^A
- %stream の ⇒# .[[state]] ~SET `writable^l, .[[storedError]] ~SET ~undefined, .[[writer]] ~SET ~undefined, .[[writableStreamController]] ~SET ~undefined, .[[inFlightWriteRequest]] ~SET ~undefined, .[[closeRequest]] ~SET ~undefined, .[[inFlightCloseRequest]] ~SET ~undefined, .[[pendingAbortRequest]] ~SET ~undefined, .[[writeRequests]] ~SET 新たな空`~List$, .[[backpressure]] ~SET ~false ◎ Set stream.[[state]] to "writable". ◎ Set stream.[[storedError]], stream.[[writer]], stream.[[writableStreamController]], stream.[[inFlightWriteRequest]], stream.[[closeRequest]], stream.[[inFlightCloseRequest]] and stream.[[pendingAbortRequest]] to undefined. ◎ Set stream.[[writeRequests]] to a new empty List. ◎ Set stream.[[backpressure]] to false.
4.3.4. `IsWritableStream( x )^A
- ~IF[ `Type$A( %x ) ~NEQ `Object^b ] ⇒ ~RET ~false ◎ If Type(x) is not Object, return false.
- ~IF[ %x は [[writableStreamController]] 内部~slotを持たない ] ⇒ ~RET ~false ◎ If x does not have a [[writableStreamController]] internal slot, return false.
- ~RET ~true ◎ Return true.
4.3.5. `IsWritableStreamLocked( stream )^A
この抽象~演算は、[ 可書~streamが書込器に`~lockされて$いるかどうか ]を照会したいと望むような,他の仕様から~callされる用途に意味されている。 ◎ This abstract operation is meant to be called from other specifications that may wish to query whether or not a writable stream is locked to a writer.
- ~Assert: ! `IsWritableStream$A( %stream ) ~EQ ~true ◎ Assert: ! IsWritableStream(stream) is true.
- ~IF[ %stream.[[writer]] ~EQ ~undefined ] ⇒ ~RET ~false ◎ If stream.[[writer]] is undefined, return false.
- ~RET ~true ◎ Return true.
4.3.6. `WritableStreamAbort( stream, reason )^A
- %state ~LET %stream.[[state]] ◎ Let state be stream.[[state]].
- ~IF[ %state ~IN { `closed^l, `errored^l } ] ⇒ ~RET ~undefined で`解決される~promise$ ◎ If state is "closed" or "errored", return a promise resolved with undefined.
- ~IF[ %stream.[[pendingAbortRequest]] ~NEQ ~undefined ] ⇒ ~RET %stream.[[pendingAbortRequest]].[[promise]] ◎ If stream.[[pendingAbortRequest]] is not undefined, return stream.[[pendingAbortRequest]].[[promise]].
- ~Assert: %state ~IN { `writable^l, `erroring^l } ◎ Assert: state is "writable" or "erroring".
- %wasAlreadyErroring ~LET ~false ◎ Let wasAlreadyErroring be false.
-
~IF[ %state ~EQ `erroring^l ]: ◎ If state is "erroring",
- %wasAlreadyErroring ~SET ~true ◎ Set wasAlreadyErroring to true.
- %reason ~SET ~undefined ◎ Set reason to undefined.
- %promise ~LET `新たな~promise$ ◎ Let promise be a new promise.
- %stream.[[pendingAbortRequest]] ~SET `~Record$ { [[promise]]: %promise, [[reason]]: %reason, [[wasAlreadyErroring]]: %wasAlreadyErroring } ◎ Set stream.[[pendingAbortRequest]] to Record {[[promise]]: promise, [[reason]]: reason, [[wasAlreadyErroring]]: wasAlreadyErroring}.
- ~IF[ %wasAlreadyErroring ~EQ ~false ] ⇒ ! `WritableStreamStartErroring$A( %stream, %reason ) ◎ If wasAlreadyErroring is false, perform ! WritableStreamStartErroring(stream, reason).
- ~RET %promise ◎ Return promise.
4.4. 制御器により利用される可書~stream抽象~演算
将来に,挙動が異なる可書~stream(既定の可読~streamと`可読~byte~stream$との間の区別に類似するような)も追加できるような柔軟性を得るため、`可書~stream$の内部~状態の多くの部分は, `WritableStreamDefaultController$C ~classにより~encapsulateされる。 ◎ To allow future flexibility to add different writable stream behaviors (similar to the distinction between default readable streams and readable byte streams), much of the internal state of a writable stream is encapsulated by the WritableStreamDefaultController class.
この節における抽象~演算は、結付けられている `WritableStream$C ~objに影響するような,制御器~実装により利用される~interfaceである。 制御器の内部~状態における変化は、 `WritableStream$C の~public~APIを通して可視になるように,開発者が面する結果に翻訳される。 ◎ The abstract operations in this section are interfaces that are used by the controller implementation to affect its associated WritableStream object, translating the controller’s internal state changes into developer-facing results visible through the WritableStream's public API.
4.4.1. `WritableStreamAddWriteRequest( stream )^A
- ~Assert: ! `IsWritableStreamLocked$A( %stream ) ~EQ ~true ◎ Assert: ! IsWritableStreamLocked(stream) is true.
- ~Assert: %stream.[[state]] ~EQ `writable^l ◎ Assert: stream.[[state]] is "writable".
- %promise ~LET `新たな~promise$ ◎ Let promise be a new promise.
- %stream.[[writeRequests]] の~~末尾に %promise を付加する ◎ Append promise as the last element of stream.[[writeRequests]].
- ~RET %promise ◎ Return promise.
4.4.2. `WritableStreamDealWithRejection( stream, error )^A
- %state ~LET %stream.[[state]] ◎ Let state be stream.[[state]].
-
~IF[ %state ~EQ `writable^l ]: ◎ If state is "writable",
- ! `WritableStreamStartErroring$A( %stream, %error ) ◎ Perform ! WritableStreamStartErroring(stream, error).
- ~RET ◎ Return.
- ~Assert: %state ~EQ `erroring^l ◎ Assert: state is "erroring".
- ! `WritableStreamFinishErroring$A( %stream ) ◎ Perform ! WritableStreamFinishErroring(stream).
4.4.3. `WritableStreamStartErroring( stream, reason )^A
- ~Assert: %stream.[[storedError]] ~EQ ~undefined ◎ Assert: stream.[[storedError]] is undefined.
- ~Assert: %stream.[[state]] ~EQ `writable^l ◎ Assert: stream.[[state]] is "writable".
- %controller ~LET %stream.[[writableStreamController]] ◎ Let controller be stream.[[writableStreamController]].
- ~Assert: %controller ~NEQ ~undefined ◎ Assert: controller is not undefined.
- %stream.[[state]] ~SET `erroring^l ◎ Set stream.[[state]] to "erroring".
- Set stream.[[storedError]] to reason.
- %writer ~LET %stream.[[writer]] ◎ Let writer be stream.[[writer]].
- ~IF[ %writer ~NEQ ~undefined ] ⇒ ! `WritableStreamDefaultWriterEnsureReadyPromiseRejected$A( %writer, %reason ) ◎ If writer is not undefined, perform ! WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason).
- ~IF[ ! `WritableStreamHasOperationMarkedInFlight$A( %stream ) ~EQ ~false ]~AND[ %controller.[[started]] ~EQ ~true ] ⇒ ! `WritableStreamFinishErroring$A( %stream ) ◎ If ! WritableStreamHasOperationMarkedInFlight(stream) is false and controller.[[started]] is true, perform ! WritableStreamFinishErroring(stream).
4.4.4. `WritableStreamFinishErroring( stream )^A
- ~Assert: %stream.[[state]] ~EQ `erroring^l ◎ Assert: stream.[[state]] is "erroring".
- ~Assert: ! `WritableStreamHasOperationMarkedInFlight$A( %stream ) ~EQ ~false ◎ Assert: ! WritableStreamHasOperationMarkedInFlight(stream) is false.
- %stream.[[state]] ~SET `errored^l ◎ Set stream.[[state]] to "errored".
- ! %stream.[[writableStreamController]].[[ErrorSteps]]() ◎ Perform ! stream.[[writableStreamController]].[[ErrorSteps]]().
- %storedError ~LET %stream.[[storedError]] ◎ Let storedError be stream.[[storedError]].
-
%stream.[[writeRequests]] 内の~EACH ( %writeRequest ) に対し: ◎ Repeat for each writeRequest that is an element of stream.[[writeRequests]],
- %storedError で %writeRequest を`却下する$ ◎ Reject writeRequest with storedError.
- %stream.[[writeRequests]] ~SET 空`~List$ ◎ Set stream.[[writeRequests]] to an empty List.
-
~IF[ %stream.[[pendingAbortRequest]] ~EQ ~undefined ]: ◎ If stream.[[pendingAbortRequest]] is undefined,
- ! `WritableStreamRejectCloseAndClosedPromiseIfNeeded$A( %stream) ◎ Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream).
- ~RET ◎ Return.
- %abortRequest ~LET %stream.[[pendingAbortRequest]] ◎ Let abortRequest be stream.[[pendingAbortRequest]].
- %stream.[[pendingAbortRequest]] ~SET ~undefined ◎ Set stream.[[pendingAbortRequest]] to undefined.
-
~IF[ %abortRequest.[[wasAlreadyErroring]] ~EQ ~true ]: ◎ If abortRequest.[[wasAlreadyErroring]] is true,
- %storedError で %abortRequest.[[promise]] を`却下する$ ◎ Reject abortRequest.[[promise]] with storedError.
- ! `WritableStreamRejectCloseAndClosedPromiseIfNeeded$A( %stream) ◎ Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream).
- ~RET ◎ Return.
-
%promise ~LET ! %stream.[[writableStreamController]].[[AbortSteps]]( %abortRequest.[[reason]] ) ◎ Let promise be ! stream.[[writableStreamController]].[[AbortSteps]](abortRequest.[[reason]]).
-
%promise の`充足-時$には ◎ Upon fulfillment of promise,
- ~undefined で %abortRequest.[[promise]] を`解決する$ ◎ Resolve abortRequest.[[promise]] with undefined.
- ! `WritableStreamRejectCloseAndClosedPromiseIfNeeded$A( %stream) ◎ Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream).
-
事由 %reason による %promise の`却下-時$には: ◎ Upon rejection of promise with reason reason,
- %reason で %abortRequest.[[promise]] を`却下する$ ◎ Reject abortRequest.[[promise]] with reason.
- ! `WritableStreamRejectCloseAndClosedPromiseIfNeeded$A( %stream) ◎ Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream).
-
4.4.5. `WritableStreamFinishInFlightWrite( stream )^A
- ~Assert: %stream.[[inFlightWriteRequest]] ~NEQ ~undefined ◎ Assert: stream.[[inFlightWriteRequest]] is not undefined.
- ~undefined で %stream.[[inFlightWriteRequest]] を`解決する$ ◎ Resolve stream.[[inFlightWriteRequest]] with undefined.
- %stream.[[inFlightWriteRequest]] ~SET ~undefined ◎ Set stream.[[inFlightWriteRequest]] to undefined.
4.4.6. `WritableStreamFinishInFlightWriteWithError( stream, error )^A
- ~Assert: %stream.[[inFlightWriteRequest]] ~NEQ ~undefined ◎ Assert: stream.[[inFlightWriteRequest]] is not undefined.
- %error で %stream.[[inFlightWriteRequest]] を`却下する$ ◎ Reject stream.[[inFlightWriteRequest]] with error.
- %stream.[[inFlightWriteRequest]] ~SET ~undefined ◎ Set stream.[[inFlightWriteRequest]] to undefined.
- ~Assert: %stream.[[state]] ~IN { `writable^l, `erroring^l } ◎ Assert: stream.[[state]] is "writable" or "erroring".
- ! `WritableStreamDealWithRejection$A( %stream, %error ) ◎ Perform ! WritableStreamDealWithRejection(stream, error).
4.4.7. `WritableStreamFinishInFlightClose( stream )^A
- ~Assert: %stream.[[inFlightCloseRequest]] ~NEQ ~undefined ◎ Assert: stream.[[inFlightCloseRequest]] is not undefined.
- ~undefined で %stream.[[inFlightCloseRequest]] を`解決する$ ◎ Resolve stream.[[inFlightCloseRequest]] with undefined.
- %stream.[[inFlightCloseRequest]] ~SET ~undefined ◎ Set stream.[[inFlightCloseRequest]] to undefined.
- %state ~LET %stream.[[state]] ◎ Let state be stream.[[state]].
- ~Assert: %stream.[[state]] ~IN { `writable^l, `erroring^l } ◎ Assert: stream.[[state]] is "writable" or "erroring".
-
~IF[ %state ~EQ `erroring^l ]: ◎ If state is "erroring",
- %stream.[[storedError]] ~SET ~undefined ◎ Set stream.[[storedError]] to undefined.
-
~IF[ %stream.[[pendingAbortRequest]] ~NEQ ~undefined ]: ◎ If stream.[[pendingAbortRequest]] is not undefined,
- ~undefined で %stream.[[pendingAbortRequest]].[[promise]] を`解決する$ ◎ Resolve stream.[[pendingAbortRequest]].[[promise]] with undefined.
- %stream.[[pendingAbortRequest]] ~SET ~undefined ◎ Set stream.[[pendingAbortRequest]] to undefined.
- %stream.[[state]] ~SET `closed^l ◎ Set stream.[[state]] to "closed".
- %writer ~LET %stream.[[writer]] ◎ Let writer be stream.[[writer]].
- ~IF[ %writer ~NEQ ~undefined ] ⇒ ~undefined で %writer.[[closedPromise]] を`解決する$ ◎ If writer is not undefined, resolve writer.[[closedPromise]] with undefined.
- ~Assert: %stream.[[pendingAbortRequest]] ~EQ ~undefined ◎ Assert: stream.[[pendingAbortRequest]] is undefined.
- ~Assert: %stream.[[storedError]] ~EQ ~undefined ◎ Assert: stream.[[storedError]] is undefined.
4.4.8. `WritableStreamFinishInFlightCloseWithError( stream, error )^A
- ~Assert: %stream.[[inFlightCloseRequest]] ~NEQ ~undefined ◎ Assert: stream.[[inFlightCloseRequest]] is not undefined.
- %error で %stream.[[inFlightCloseRequest]] を`却下する$ ◎ Reject stream.[[inFlightCloseRequest]] with error.
- %stream.[[inFlightCloseRequest]] ~SET ~undefined ◎ Set stream.[[inFlightCloseRequest]] to undefined.
- ~Assert: %stream.[[state]] ~IN { `writable^l, `erroring^l } ◎ Assert: stream.[[state]] is "writable" or "erroring".
-
~IF[ %stream.[[pendingAbortRequest]] ~NEQ ~undefined ]: ◎ If stream.[[pendingAbortRequest]] is not undefined,
- %error で %stream.[[pendingAbortRequest]].[[promise]] を`却下する$ ◎ Reject stream.[[pendingAbortRequest]].[[promise]] with error.
- %stream.[[pendingAbortRequest]] ~SET ~undefined ◎ Set stream.[[pendingAbortRequest]] to undefined.
- ! `WritableStreamDealWithRejection$A( %stream, %error ) ◎ Perform ! WritableStreamDealWithRejection(stream, error).
4.4.9. `WritableStreamCloseQueuedOrInFlight( stream )^A
- ~IF[ %stream.[[closeRequest]] ~EQ ~undefined ]~AND[ %stream.[[inFlightCloseRequest]] ~EQ ~undefined ] ⇒ ~RET ~false ◎ If stream.[[closeRequest]] is undefined and stream.[[inFlightCloseRequest]] is undefined, return false.
- ~RET ~true ◎ Return true.
4.4.10. `WritableStreamHasOperationMarkedInFlight( stream )^A
- ~IF[ %stream.[[inFlightWriteRequest]] ~EQ ~undefined ]~AND[ %controller.[[inFlightCloseRequest]] ~EQ ~undefined ] ⇒ ~RET ~false ◎ If stream.[[inFlightWriteRequest]] is undefined and controller.[[inFlightCloseRequest]] is undefined, return false.
- ~RET ~true ◎ Return true.
4.4.11. `WritableStreamMarkCloseRequestInFlight( stream )^A
- ~Assert: %stream.[[inFlightCloseRequest]] ~EQ ~undefined ◎ Assert: stream.[[inFlightCloseRequest]] is undefined.
- ~Assert: %stream.[[closeRequest]] ~NEQ ~undefined ◎ Assert: stream.[[closeRequest]] is not undefined.
- %stream.[[inFlightCloseRequest]] ~SET %stream.[[closeRequest]] ◎ Set stream.[[inFlightCloseRequest]] to stream.[[closeRequest]].
- %stream.[[closeRequest]] ~SET ~undefined ◎ Set stream.[[closeRequest]] to undefined.
4.4.12. `WritableStreamMarkFirstWriteRequestInFlight( stream )^A
- ~Assert: %stream.[[inFlightWriteRequest]] ~EQ ~undefined ◎ Assert: stream.[[inFlightWriteRequest]] is undefined.
- ~Assert: %stream.[[writeRequests]] は空でない ◎ Assert: stream.[[writeRequests]] is not empty.
- %writeRequest ~LET %stream.[[writeRequests]] の最初の要素 ◎ Let writeRequest be the first element of stream.[[writeRequests]].
- %stream.[[writeRequests]] から %writeRequest を除去する — 後続の要素たちは~~先頭へ一つずらす ◎ Remove writeRequest from stream.[[writeRequests]], shifting all other elements downward (so that the second becomes the first, and so on).
- %stream.[[inFlightWriteRequest]] ~SET %writeRequest ◎ Set stream.[[inFlightWriteRequest]] to writeRequest.
4.4.13. `WritableStreamRejectCloseAndClosedPromiseIfNeeded( stream )^A
- ~Assert: %stream.[[state]] ~EQ `errored^l ◎ Assert: stream.[[state]] is "errored".
-
~IF[ %stream.[[pendingCloseRequest]] ~NEQ ~undefined ]: ◎ If stream.[[closeRequest]] is not undefined,
- ~Assert: %stream.[[inFlightCloseRequest]] ~EQ ~undefined ◎ Assert: stream.[[inFlightCloseRequest]] is undefined.
- %stream.[[storedError]] で %stream.[[closeRequest]] を`却下する$ ◎ Reject stream.[[closeRequest]] with stream.[[storedError]].
- %stream.[[closeRequest]] ~SET ~undefined ◎ Set stream.[[closeRequest]] to undefined.
- %writer ~LET %stream.[[writer]] ◎ Let writer be stream.[[writer]].
-
~IF[ %writer ~NEQ ~undefined ]: ◎ If writer is not undefined,
- %stream.[[storedError]] で %writer.[[closedPromise]] を`却下する$ ◎ Reject writer.[[closedPromise]] with stream.[[storedError]].
- %writer.[[closedPromise]].[[PromiseIsHandled]] ~SET ~true ◎ Set writer.[[closedPromise]].[[PromiseIsHandled]] to true.
4.4.14. `WritableStreamUpdateBackpressure( stream, backpressure )^A
- ~Assert: %stream.[[state]] ~EQ `writable^l ◎ Assert: stream.[[state]] is "writable".
- ~Assert: ! `WritableStreamCloseQueuedOrInFlight$A( %stream ) ~EQ ~false ◎ Assert: ! WritableStreamCloseQueuedOrInFlight(stream) is false.
- %writer ~LET %stream.[[writer]] ◎ Let writer be stream.[[writer]].
-
~IF[ %writer ~NEQ ~undefined ]~AND[ %backpressure ~NEQ %stream.[[backpressure]] ]: ◎ If writer is not undefined and backpressure is not stream.[[backpressure]],
- ~IF[ %backpressure ~EQ ~true ] ⇒ %writer.[[readyPromise]] ~SET `新たな~promise$ ◎ If backpressure is true, set writer.[[readyPromise]] to a new promise.
-
~ELSE: ◎ Otherwise,
- ~Assert: %backpressure ~EQ ~false ◎ Assert: backpressure is false.
- ~undefined で %writer.[[readyPromise]] を`解決する$ ◎ Resolve writer.[[readyPromise]] with undefined.
- %stream.[[backpressure]] ~SET %backpressure ◎ Set stream.[[backpressure]] to backpressure.
4.5. `WritableStreamDefaultWriter^C ~class
`WritableStreamDefaultWriter$C ~classは、[ `WritableStream$C ~instanceから配給されるように設計された`可書~stream書込器$ ]を表現する。 ◎ The WritableStreamDefaultWriter class represents a writable stream writer designed to be vended by a WritableStream instance.
4.5.1. ~class定義
~INFORMATIVE`WritableStreamDefaultWriter$C ~classは、 `ECMASCRIPT$r 風の構文で書くならば,次のようになる: ◎ If one were to write the WritableStreamDefaultWriter class in something close to the syntax of [ECMASCRIPT], it would look like
class WritableStreamDefaultWriter { `constructor(stream)$dw get `closed()$dw get `desiredSize()$dw get `ready()$dw `abort(reason)$dw `close()$dw `releaseLock()$dw `write(chunk)$dw }
4.5.2. 各種 内部~slot
`WritableStreamDefaultWriter$C の各~instanceは、次の一覧に述べる各種 内部~slotを伴って作成される: ◎ Instances of WritableStreamDefaultWriter are created with the internal slots described in the following table:
内部~slot | 説明0(参考) |
---|---|
[[closedPromise]] | 書込器の `closed()$dw 取得子から返される~promise ◎ A promise returned by the writer’s closed getter |
[[ownerWritableStream]] | この書込器を所有する `WritableStream$C の~instance ◎ A WritableStream instance that owns this writer |
[[readyPromise]] | 書込器の `ready$dw 取得子から返される~promise ◎ A promise returned by the writer’s ready getter |
4.5.3. `new WritableStreamDefaultWriter( stream )^dw
`WritableStreamDefaultWriter()^dw 構築子は、一般に,直接的な利用は意味されていない — 代わりに,~streamの `getWriter()$ws ~methodが利用されるべきである。 ◎ The WritableStreamDefaultWriter constructor is generally not meant to be used directly; instead, a stream’s getWriter() method ought to be used.
- ~IF[ ! `IsWritableStream$A( %stream ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsWritableStream(stream) is false, throw a TypeError exception.
- ~IF[ ! `IsWritableStreamLocked$A( %stream ) ~EQ ~true ] ⇒ ~THROW `TypeError^b ◎ If ! IsWritableStreamLocked(stream) is true, throw a TypeError exception.
- ~this.[[ownerWritableStream]] ~SET %stream ◎ Set this.[[ownerWritableStream]] to stream.
- %stream.[[writer]] ~SET ~this ◎ Set stream.[[writer]] to this.
- %state ~LET %stream.[[state]] ◎ Let state be stream.[[state]].
-
~IF[ %state ~EQ `writable^l ]: ◎ If state is "writable",
- ~IF[ ! `WritableStreamCloseQueuedOrInFlight$A( %stream ) ~EQ ~false ]~AND[ %stream.[[backpressure]] ~EQ ~true ] ⇒ ~this.[[readyPromise]] ~SET `新たな~promise$ ◎ If ! WritableStreamCloseQueuedOrInFlight(stream) is false and stream.[[backpressure]] is true, set this.[[readyPromise]] to a new promise.
- ~ELSE ⇒ ~this.[[readyPromise]] ~SET ~undefined で`解決される~promise$ ◎ Otherwise, set this.[[readyPromise]] to a promise resolved with undefined.
- ~this.[[closedPromise]] ~SET `新たな~promise$ ◎ Set this.[[closedPromise]] to a new promise.
-
~ELIF %state ~EQ `erroring^l : ◎ Otherwise, if state is "erroring",
- ~this.[[readyPromise]] ~SET %stream.[[storedError]] で`却下される~promise$ ◎ Set this.[[readyPromise]] to a promise rejected with stream.[[storedError]].
- ~this.[[readyPromise]].[[PromiseIsHandled]] ~SET ~true ◎ Set this.[[readyPromise]].[[PromiseIsHandled]] to true.
- ~this.[[closedPromise]] ~SET `新たな~promise$ ◎ Set this.[[closedPromise]] to a new promise.
-
~ELIF %state ~EQ `closed^l : ◎ Otherwise, if state is "closed",
- ~this.[[readyPromise]] ~SET ~undefined で`解決される~promise$ ◎ Set this.[[readyPromise]] to a promise resolved with undefined.
- ~this.[[closedPromise]] ~SET ~undefined で`解決される~promise$ ◎ Set this.[[closedPromise]] to a promise resolved with undefined.
-
~ELSE: ◎ Otherwise,
- ~Assert: %state ~EQ `errored^l ◎ Assert: state is "errored".
- %storedError ~LET %stream.[[storedError]] ◎ Let storedError be stream.[[storedError]].
- ~this.[[readyPromise]] ~SET %storedError で`却下される~promise$ ◎ Set this.[[readyPromise]] to a promise rejected with storedError.
- ~this.[[readyPromise]].[[PromiseIsHandled]] ~SET ~true ◎ Set this.[[readyPromise]].[[PromiseIsHandled]] to true.
- ~this.[[closedPromise]] ~SET %storedError で`却下される~promise$ ◎ Set this.[[closedPromise]] to a promise rejected with storedError.
- ~this.[[closedPromise]].[[PromiseIsHandled]] ~SET ~true ◎ Set this.[[closedPromise]].[[PromiseIsHandled]] to true.
4.5.4. `WritableStreamDefaultWriter^C ~prototypeの各種~prop
4.5.4.1. `get closed^dw
`closed^m 取得子は、~promiseを返す。 それは、~streamが~closeされたときは充足され,[ どこかで~errorした / ~streamが~closeし終える前に書込器の~lockが`解放-$された ]ときは却下される。 ◎ The closed getter returns a promise that will be fulfilled when the stream becomes closed, or rejected if the stream ever errors or the writer’s lock is released before the stream finishes closing.
- ~IF[ ! `IsWritableStreamDefaultWriter$A( ~this ) ~EQ ~false ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsWritableStreamDefaultWriter(this) is false, return a promise rejected with a TypeError exception.
- ~RET ~this.[[closedPromise]] ◎ Return this.[[closedPromise]].
4.5.4.2. `get desiredSize^dw
`desiredSize^m 取得子は、`~streamの内部~queueの残り~size$を返す。 ~queueを溢れている場合の結果は、負になる。 `生産器$は、書込する正解の~data量を決定するときに,この情報を利用できる。 ◎ The desiredSize getter returns the desired size to fill the stream’s internal queue. It can be negative, if the queue is over-full. A producer can use this information to determine the right amount of data to write.
~streamを成功裡に書込できない場合(~errorになったか~queue-upが中止されたことに因り)、 `null^b になる。 ~streamが~closeされた場合、 0 になる。 この取得子が,書込器の~lockが`解放-$されている間に呼出された場合、例外を投出する。 ◎ It will be null if the stream cannot be successfully written to (due to either being errored, or having an abort queued up). It will return zero if the stream is closed. The getter will throw an exception if invoked when the writer’s lock is released.
- ~IF[ ! `IsWritableStreamDefaultWriter$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsWritableStreamDefaultWriter(this) is false, throw a TypeError exception.
- ~IF[ ~this.[[ownerWritableStream]] ~EQ ~undefined ] ⇒ ~THROW `TypeError^b ◎ If this.[[ownerWritableStream]] is undefined, throw a TypeError exception.
- ~RET ! `WritableStreamDefaultWriterGetDesiredSize$A( ~this ) ◎ Return ! WritableStreamDefaultWriterGetDesiredSize(this).
4.5.4.3. `get ready^dw
`ready^dw 取得子は、`~streamの内部~queueの残り~size$が 0 以下から正へ遷移したとき — それは,`背圧$は適用されないことを合図する — に充足されることになる,~promiseを返す。 `~streamの内部~queueの残り~size$が また 0 以下に落ち込んだときには、取得子は,[ 次回の遷移まで処理待ちであり続ける,`新たな~promise$ ]を返すことになる。 ◎ The ready getter returns a promise that will be fulfilled when the desired size to fill the stream’s internal queue transitions from non-positive to positive, signaling that it is no longer applying backpressure. Once the desired size to fill the stream’s internal queue dips back to zero or below, the getter will return a new promise that stays pending until the next transition.
~streamが~errorになったか中止された, または 書込器の~lockが`解放-$された場合、返された~promiseは,却下されることになる。 ◎ If the stream becomes errored or aborted, or the writer’s lock is released, the returned promise will become rejected.
- ~IF[ ! `IsWritableStreamDefaultWriter$A( ~this ) ~EQ ~false ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsWritableStreamDefaultWriter(this) is false, return a promise rejected with a TypeError exception.
- ~RET ~this.[[readyPromise]] ◎ Return this.[[readyPromise]].
4.5.4.4. `abort( reason )^dw
書込器が`作動中$にある場合、 `abort()^m ~methodは、結付けられている~stream用のそれと同じに挙動する(他の場合,それは却下される~promiseを返す。) ◎ If the writer is active, the abort method behaves the same as that for the associated stream. (Otherwise, it returns a rejected promise.)
- ~IF[ ! `IsWritableStreamDefaultWriter$A( ~this ) ~EQ ~false ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsWritableStreamDefaultWriter(this) is false, return a promise rejected with a TypeError exception.
- ~IF[ ~this.[[ownerWritableStream]] ~EQ ~undefined ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If this.[[ownerWritableStream]] is undefined, return a promise rejected with a TypeError exception.
- ~RET ! `WritableStreamDefaultWriterAbort$A( ~this, %reason ) ◎ Return ! WritableStreamDefaultWriterAbort(this, reason).
4.5.4.5. `close()^dw
`close()^dw ~methodは、結付けられている可書~streamを~closeする。 `下層~槽$は、自身の~close挙動を呼出す前に,以前に書込された`~chunk$を処理し終えることになる。 その間,更に書込しようとする試みは、失敗することになる(~streamを~errorにすることなく)。 ◎ The close method will close the associated writable stream. The underlying sink will finish processing any previously-written chunks, before invoking its close behavior. During this time any further attempts to write will fail (without erroring the stream).
この~methodは、~promiseを返す — それは、残りの`~chunk$すべてが成功裡に書込され,~stream成功裡に~closeしたなら,~undefined で充足される。 この処理の間に~errorに遭遇した場合は却下される。 ◎ The method returns a promise that is fulfilled with undefined if all remaining chunks are successfully written and the stream successfully closes, or rejects if an error is encountered during this process.
- ~IF[ ! `IsWritableStreamDefaultWriter$A( ~this ) ~EQ ~false ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsWritableStreamDefaultWriter(this) is false, return a promise rejected with a TypeError exception.
- %stream ~LET ~this.[[ownerWritableStream]] ◎ Let stream be this.[[ownerWritableStream]].
- ~IF[ %stream ~EQ ~undefined ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If stream is undefined, return a promise rejected with a TypeError exception.
- ~IF[ ! `WritableStreamCloseQueuedOrInFlight$A( %stream ) ~EQ ~true ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! WritableStreamCloseQueuedOrInFlight(stream) is true, return a promise rejected with a TypeError exception.
- ~RET ! `WritableStreamDefaultWriterClose$A( ~this ) ◎ Return ! WritableStreamDefaultWriterClose(this).
4.5.4.6. `releaseLock()^dw
`releaseLock()^dw ~methodは、書込器による対応する~stream上の~lockを`解放-$する。 ~lockが解放されて以降は、当の書込器は,最早 `作動中$でなくなる。 ~lockが解放される時点で,結付けられている~streamが~error状態にある場合、それ以降も,書込器はそれを引き継ぐように~errorしたように現れる。 他の場合、書込器は~closeされたように現れる。 ◎ The releaseLock method releases the writer’s lock on the corresponding stream. After the lock is released, the writer is no longer active. If the associated stream is errored when the lock is released, the writer will appear errored in the same way from now on; otherwise, the writer will appear closed.
まだ完遂してない進行中の書込があるときでも(すなわち、前回の `write()$dw ~callから返された~promiseが決着していなくとも)、~lockは解放できることに注意。 書込~中に書込器~上の~lockを保持することは必要とされない — ~lockは、単純に,他の生産器が差挟むような方式で書込するのを防止するためにある。 ◎ Note that the lock can still be released even if some ongoing writes have not yet finished (i.e. even if the promises returned from previous calls to write() have not yet settled). It’s not necessary to hold the lock on the writer for the duration of the write; the lock instead simply prevents other producers from writing in an interleaved manner.
- ~IF[ ! `IsWritableStreamDefaultWriter$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsWritableStreamDefaultWriter(this) is false, throw a TypeError exception.
- %stream ~LET ~this.[[ownerWritableStream]] ◎ Let stream be this.[[ownerWritableStream]].
- ~IF[ %stream ~EQ ~undefined ] ⇒ ~RET ◎ If stream is undefined, return.
- ~Assert: %stream.[[writer]] ~NEQ ~undefined ◎ Assert: stream.[[writer]] is not undefined.
- ! `WritableStreamDefaultWriterRelease$A( ~this ) ◎ Perform ! WritableStreamDefaultWriterRelease(this).
4.5.4.7. `write( chunk )^dw
`write()^dw ~methodは、所与の`~chunk$を可書~streamに書込する — 以前の書込があれば それが成功裡に完遂するまで待機した上で,`下層~槽$の `write()$snk ~methodに`~chunk$を送信することにより。 この~methodは、~promiseを返す。 この~promiseは、書込が成功したときは ~undefined で充足され,[ 書込に失敗したとき, または書込み処理が起動される前に~streamが~errorした場合 ]は 却下される。 ◎ The write method writes the given chunk to the writable stream, by waiting until any previous writes have finished successfully, and then sending the chunk to the underlying sink’s write() method. It will return a promise that fulfills with undefined upon a successful write, or rejects if the write fails or stream becomes errored before the writing process is initiated.
注記: “成功” が 何を意味するかは,`下層~槽$に委ねられる。 それは、単純に`~chunk$が受容されたことを指示するだけかもしれない — それが最終~行先に安全に保存されることは,必要とされない。 ◎ Note that what "success" means is up to the underlying sink; it might indicate simply that the chunk has been accepted, and not necessarily that it is safely saved to its ultimate destination.
- ~IF[ ! `IsWritableStreamDefaultWriter$A( ~this ) ~EQ ~false ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If ! IsWritableStreamDefaultWriter(this) is false, return a promise rejected with a TypeError exception.
- ~IF[ ~this.[[ownerWritableStream]] ~EQ ~undefined ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If this.[[ownerWritableStream]] is undefined, return a promise rejected with a TypeError exception.
- ~RET ! `WritableStreamDefaultWriterWrite$A( ~this, %chunk ) ◎ Return ! WritableStreamDefaultWriterWrite(this, chunk).
4.6. 可書~stream書込器~用の抽象~演算
4.6.1. `IsWritableStreamDefaultWriter( x )^A
- ~IF[ `Type$A( %x ) ~NEQ `Object^b ] ⇒ ~RET ~false ◎ If Type(x) is not Object, return false.
- ~IF[ %x は [[ownerWritableStream]] 内部~slotを持たない ] ⇒ ~RET ~false ◎ If x does not have an [[ownerWritableStream]] internal slot, return false.
- ~RET ~true ◎ Return true.
4.6.2. `WritableStreamDefaultWriterAbort( writer, reason )^A
- %stream ~LET %writer.[[ownerWritableStream]] ◎ Let stream be writer.[[ownerWritableStream]].
- ~Assert: %stream ~NEQ ~undefined ◎ Assert: stream is not undefined.
- ~RET ! `WritableStreamAbort$A( %stream, %reason ) ◎ Return ! WritableStreamAbort(stream, reason).
4.6.3. `WritableStreamDefaultWriterClose( writer )^A
- %stream ~LET %writer.[[ownerWritableStream]] ◎ Let stream be writer.[[ownerWritableStream]].
- ~Assert: %stream ~NEQ ~undefined ◎ Assert: stream is not undefined.
- %state ~LET %stream.[[state]] ◎ Let state be stream.[[state]].
- ~IF[ %state ~IN { `closed^l, `errored^l } ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If state is "closed" or "errored", return a promise rejected with a TypeError exception.
- ~Assert: %state ~IN { `writable^l, `erroring^l } ◎ Assert: state is "writable" or "erroring".
- ~Assert: ! `WritableStreamCloseQueuedOrInFlight$A( %stream ) ~EQ ~false ◎ Assert: ! WritableStreamCloseQueuedOrInFlight(stream) is false.
- %promise ~LET `新たな~promise$ ◎ Let promise be a new promise.
- %stream.[[closeRequest]] ~SET %promise ◎ Set stream.[[closeRequest]] to promise.
- ~IF[ %stream.[[backpressure]] ~EQ ~true ]~AND[ %state ~EQ `writable^l ] ⇒ ~undefined で %writer.[[readyPromise]] を`解決する$ ◎ If stream.[[backpressure]] is true and state is "writable", resolve writer.[[readyPromise]] with undefined.
- ! `WritableStreamDefaultControllerClose$A( %stream.[[writableStreamController]] ) ◎ Perform ! WritableStreamDefaultControllerClose(stream.[[writableStreamController]]).
- ~RET %promise ◎ Return promise.
4.6.4. `WritableStreamDefaultWriterCloseWithErrorPropagation( writer )^A
注記: この抽象~演算は、 `pipeTo()$rs における~error伝播の意味論を実装し易くするためにある。 ◎ This abstract operation helps implement the error propagation semantics of pipeTo().
- %stream ~LET %writer.[[ownerWritableStream]] ◎ Let stream be writer.[[ownerWritableStream]].
- ~Assert: %stream ~NEQ ~undefined ◎ Assert: stream is not undefined.
- %state ~LET %stream.[[state]] ◎ Let state be stream.[[state]].
- ~IF[ ! `WritableStreamCloseQueuedOrInFlight$A( %stream ) ~EQ ~true ]~OR[ %state ~EQ `closed^l ] ⇒ ~RET ~undefined で`解決される~promise$ ◎ If ! WritableStreamCloseQueuedOrInFlight(stream) is true or state is "closed", return a promise resolved with undefined.
- ~IF[ %state ~EQ `errored^l ] ⇒ ~RET %stream.[[storedError]] で`却下される~promise$ ◎ If state is "errored", return a promise rejected with stream.[[storedError]].
- ~Assert: %state ~IN { `writable^l, `erroring^l } ◎ Assert: state is "writable" or "erroring".
- ~RET ! `WritableStreamDefaultWriterClose$A( %writer ) ◎ Return ! WritableStreamDefaultWriterClose(writer).
4.6.5. `WritableStreamDefaultWriterEnsureClosedPromiseRejected( writer, error )^A
- ~IF[ %writer.[[closedPromise]].[[PromiseState]] ~EQ `pending^l ] ⇒ %error で %writer.[[closedPromise]] を`却下する$ ◎ If writer.[[closedPromise]].[[PromiseState]] is "pending", reject writer.[[closedPromise]] with error.
- ~ELSE ⇒ %writer.[[closedPromise]] ~SET %error で`却下される~promise$ ◎ Otherwise, set writer.[[closedPromise]] to a promise rejected with error.
- %writer.[[closedPromise]].[[PromiseIsHandled]] ~SET ~true ◎ Set writer.[[closedPromise]].[[PromiseIsHandled]] to true.
4.6.6. `WritableStreamDefaultWriterEnsureReadyPromiseRejected( writer, error )^A
- ~IF[ %writer.[[readyPromise]].[[PromiseState]] ~EQ `pending^l ] ⇒ %error で %writer.[[readyPromise]] を`却下する$ ◎ If writer.[[readyPromise]].[[PromiseState]] is "pending", reject writer.[[readyPromise]] with error.
- ~ELSE ⇒ %writer.[[readyPromise]] ~SET %error で`却下される~promise$ ◎ Otherwise, set writer.[[readyPromise]] to a promise rejected with error.
- %writer.[[readyPromise]].[[PromiseIsHandled]] ~SET ~true ◎ Set writer.[[readyPromise]].[[PromiseIsHandled]] to true.
4.6.7. `WritableStreamDefaultWriterGetDesiredSize( writer )^A
- %stream ~LET %writer.[[ownerWritableStream]] ◎ Let stream be writer.[[ownerWritableStream]].
- %state ~LET %stream.[[state]] ◎ Let state be stream.[[state]].
- ~IF[ %state ~IN { `errored^l, `erroring^l } ] ⇒ ~RET `null^b ◎ If state is "errored" or "erroring", return null.
- ~IF[ %state ~EQ `closed^l ] ⇒ ~RET `0^b ◎ If state is "closed", return 0.
- ~RET ! `WritableStreamDefaultControllerGetDesiredSize$A( %stream.[[writableStreamController]] ) ◎ Return ! WritableStreamDefaultControllerGetDesiredSize(stream.[[writableStreamController]]).
4.6.8. `WritableStreamDefaultWriterRelease( writer )^A
- %stream ~LET %writer.[[ownerWritableStream]] ◎ Let stream be writer.[[ownerWritableStream]].
- ~Assert: %stream ~NEQ ~undefined ◎ Assert: stream is not undefined.
- ~Assert: %stream.[[writer]] ~EQ %writer ◎ Assert: stream.[[writer]] is writer.
- %releasedError ~LET 新たな `TypeError^b ◎ Let releasedError be a new TypeError.
- ! `WritableStreamDefaultWriterEnsureReadyPromiseRejected$A( %writer, %releasedError) ◎ Perform ! WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError).
- ! `WritableStreamDefaultWriterEnsureClosedPromiseRejected$A( %writer, %releasedError) ◎ Perform ! WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedError).
- %stream.[[writer]] ~SET ~undefined ◎ Set stream.[[writer]] to undefined.
- %writer.[[ownerWritableStream]] ~SET ~undefined ◎ Set writer.[[ownerWritableStream]] to undefined.
4.6.9. `WritableStreamDefaultWriterWrite( writer, chunk )^A
- %stream ~LET %writer.[[ownerWritableStream]] ◎ Let stream be writer.[[ownerWritableStream]].
- ~Assert: %stream ~NEQ ~undefined ◎ Assert: stream is not undefined.
- %controller ~LET %stream.[[writableStreamController]] ◎ Let controller be stream.[[writableStreamController]].
- %chunkSize ~LET ! `WritableStreamDefaultControllerGetChunkSize$A(%controller, %chunk) ◎ Let chunkSize be ! WritableStreamDefaultControllerGetChunkSize(controller, chunk).
- ~IF[ %stream ~NEQ %writer.[[ownerWritableStream]] ] ⇒ ~RET `TypeError^b で`却下される~promise$ ◎ If stream is not equal to writer.[[ownerWritableStream]], return a promise rejected with a TypeError exception.
- %state ~LET %stream.[[state]] ◎ Let state be stream.[[state]].
- ~IF[ %state ~EQ `errored^l ] ⇒ ~RET %stream.[[storedError]] で`却下される~promise$ ◎ If state is "errored", return a promise rejected with stream.[[storedError]].
- ~IF[ ! `WritableStreamCloseQueuedOrInFlight$A( %stream ) ~EQ ~true ]~OR[ %state ~NEQ `closed^l ] ⇒ ~RET `TypeError^b で`却下される~promise$ — これは、~streamは~close中にあるか~closeされたことを指示する。 ◎ If ! WritableStreamCloseQueuedOrInFlight(stream) is true or state is "closed", return a promise rejected with a TypeError exception indicating that the stream is closing or closed.
- ~IF[ %state ~EQ `erroring^l ] ⇒ ~RET %stream.[[storedError]] で`却下される~promise$ ◎ If state is "erroring", return a promise rejected with stream.[[storedError]].
- ~Assert: %state ~EQ `writable^l ◎ Assert: state is "writable".
- %promise ~LET ! `WritableStreamAddWriteRequest$A( %stream ) ◎ Let promise be ! WritableStreamAddWriteRequest(stream).
- ! `WritableStreamDefaultControllerWrite$A( %controller, %chunk, %chunkSize ) ◎ Perform ! WritableStreamDefaultControllerWrite(controller, chunk, chunkSize).
- ~RET %promise ◎ Return promise.
4.7. `WritableStreamDefaultController^C ~class
`WritableStreamDefaultController$C ~classは、 `WritableStream$C の状態を制御~可能にする,各種~methodを持つ。 `WritableStream$C の構築-時には、`下層~槽$には,操作するための対応する `WritableStreamDefaultController$C の~instanceが与えられる。 ◎ The WritableStreamDefaultController class has methods that allow control of a WritableStream's state. When constructing a WritableStream, the underlying sink is given a corresponding WritableStreamDefaultController instance to manipulate.
4.7.1. ~class定義
~INFORMATIVE`WritableStreamDefaultController$C ~classは、 `ECMASCRIPT$r 風の構文で書くならば,次のようになる: ◎ If one were to write the WritableStreamDefaultController class in something close to the syntax of [ECMASCRIPT], it would look like
class WritableStreamDefaultController {
`constructor()$wsdc /*
常に投出する
◎
always throws
*/
`error(e)$wsdc
}
4.7.2. 各種 内部~slot
`WritableStreamDefaultController$C の各~instanceは、次の一覧に述べる各種 内部~slotを伴って作成される: ◎ Instances of WritableStreamDefaultController are created with the internal slots described in the following table:
内部~slot | 説明0(参考) |
---|---|
[[abortAlgorithm]] | 1 個の引数(中止-事由)をとり,~promiseを返す~algo — それは、要請された中止-を`下層~槽$に通信する。 ◎ A promise-returning algorithm, taking one argument (the abort reason), which communicates a requested abort to the underlying sink |
[[closeAlgorithm]] | ~promiseを返す~algo — それは、要請された~closeを`下層~槽$に通信する。 ◎ A promise-returning algorithm which communicates a requested close to the underlying sink |
[[controlledWritableStream]] | 制御される `WritableStream$C の~instance ◎ The WritableStream instance controlled |
[[queue]] | ~streamの[ `~chunk$たちからなる内部~queue ]を表現する`~List$ 。 ◎ A List representing the stream’s internal queue of chunks |
[[queueTotalSize]] | [[queue]] 内に格納されている すべての~chunkの合計~size(`§個別~size付き~queue演算$を見よ) ◎ The total size of all the chunks stored in [[queue]] (see §6.2 Queue-with-sizes operations) |
[[started]] | 真偽~flag — `下層~槽$が開始処理【 `start()^c 】を完遂したかどうかを指示する。 ◎ A boolean flag indicating whether the underlying sink has finished starting |
[[strategyHWM]] | ~streamの`~queuing策$の一部として,~streamの作成子から給された~number — ~streamがその`下層~槽$に`背圧$を適用することになる~~基準を指示する。 ◎ A number supplied by the creator of the stream as part of the stream’s queuing strategy, indicating the point at which the stream will apply backpressure to its underlying sink |
[[strategySizeAlgorithm]] | ~streamの`~queuing策$の一部として,~enqueueされた`~chunk$たちの~sizeを計算する~algo。 ◎ An algorithm to calculate the size of enqueued chunks, as part of the stream’s queuing strategy |
[[writeAlgorithm]] | 1 個の引数(書込する~chunk)をとり,~promiseを返す~algo — それは、`下層~槽$に~dataを書込する。 ◎ A promise-returning algorithm, taking one argument (the chunk to write), which writes data to the underlying sink |
4.7.3. new `WritableStreamDefaultController()^dw
`WritableStreamDefaultController()^wsdc 構築子は、直には利用できない — `WritableStreamDefaultController$C ~instanceは、 `WritableStream$C を構築する間に自動的に作成される。 ◎ The WritableStreamDefaultController constructor cannot be used directly; WritableStreamDefaultController instances are created automatically during WritableStream construction.
- ~THROW `TypeError^b ◎ Throw a TypeError exception.
4.7.4. `WritableStreamDefaultController^C ~prototypeの各種~prop
4.7.4.1. `error( e )^dw
`error()^dw ~methodは、可書~streamを~errorにする — それに対する以降の相互作用~すべては,与えられた~error %e で失敗するようになる。 ◎ The error method will error the writable stream, making all future interactions with it fail with the given error e.
この~methodは、稀にしか利用されない — 通例的には、`下層~槽$のいずれかの~methodから,却下される~promiseを返すだけで足りるので。 しかしながら、`下層~槽$との相互作用による通常の~lifecycleの外側にある~eventに呼応して~streamが突如~shut-downされる場合には,有用になり得る。 ◎ This method is rarely used, since usually it suffices to return a rejected promise from one of the underlying sink’s methods. However, it can be useful for suddenly shutting down a stream in response to an event outside the normal lifecycle of interactions with the underlying sink.
- ~IF[ ! `IsWritableStreamDefaultController$A( ~this) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsWritableStreamDefaultController(this) is false, throw a TypeError exception.
- %state ~LET ~this.[[controlledWritableStream]].[[state]] ◎ Let state be this.[[controlledWritableStream]].[[state]].
- ~IF[ %state ~NEQ `writable^l ] ⇒ ~RET ◎ If state is not "writable", return.
- ! `WritableStreamDefaultControllerError$A( ~this, %e ) ◎ Perform ! WritableStreamDefaultControllerError(this, e).
4.7.5. 可書~streamの既定の制御器の各種 内部~method
以下のものは、各 `WritableStreamDefaultController$C ~instanceにより実装される追加の内部~methodである。 可書~stream実装は、これらの中へ~callすることになる。 ◎ The following are additional internal methods implemented by each WritableStreamDefaultController instance. The writable stream implementation will call into these.
注記: これらが抽象~演算ではなく,~methodの形をとる理由は、可書~stream実装が制御器~実装から切り離され,将来には 他の制御器で~~拡張されることを明瞭にするためである — それらの制御器がこれらの内部~methodを実装する限りにおいて。 同様の経緯は,可読~streamにも見られ、そこでは,実際には、内部~methodに相当する多形態的に利用されるような制御器~型が,複数ある。 ◎ The reason these are in method form, instead of as abstract operations, is to make it clear that the writable stream implementation is decoupled from the controller implementation, and could in the future be expanded with other controllers, as long as those controllers implemented such internal methods. A similar scenario is seen for readable streams, where there actually are multiple controller types and as such the counterpart internal methods are used polymorphically.
4.7.5.1. [[AbortSteps]]( %reason )
- %result ~LET ~this.[[abortAlgorithm]]( %reason ) ◎ Return the result of performing this.[[abortAlgorithm]], passing reason.
- ! `WritableStreamDefaultControllerClearAlgorithms$A( ~this ) ◎ Perform ! WritableStreamDefaultControllerClearAlgorithms(this).
- ~RET %result ◎ Return result.
4.7.5.2. [[ErrorSteps]]()
- ! `ResetQueue$A( ~this ) ◎ Perform ! ResetQueue(this).
4.8. 可書~streamの既定の制御器~用の抽象~演算
4.8.1. `IsWritableStreamDefaultController( x )^A
- ~IF[ `Type$A( %x ) ~NEQ `Object^b ] ⇒ ~RET ~false ◎ If Type(x) is not Object, return false.
- ~IF[ %x は [[controlledWritableStream]] 内部~slotを持たない ] ⇒ ~RET ~false ◎ If x does not have an [[controlledWritableStream]] internal slot, return false.
- ~RET ~true ◎ Return true.
4.8.2. `SetUpWritableStreamDefaultController( stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm )^A
- ~Assert: ! `IsWritableStream$A( %stream ) ~EQ ~true ◎ Assert: ! IsWritableStream(stream) is true.
- ~Assert: %stream.[[writableStreamController]] ~EQ ~undefined ◎ Assert: stream.[[writableStreamController]] is undefined.
- %controller.[[controlledWritableStream]] ~SET %stream ◎ Set controller.[[controlledWritableStream]] to stream.
- %stream.[[writableStreamController]] ~SET %controller ◎ Set stream.[[writableStreamController]] to controller.
- ! `ResetQueue$A( %controller ) ◎ Perform ! ResetQueue(controller).
- %controller の ⇒# .[[started]] ~SET ~false, .[[strategySizeAlgorithm]] ~SET %sizeAlgorithm, .[[strategyHWM]] ~SET %highWaterMark, .[[writeAlgorithm]] ~SET %writeAlgorithm, .[[closeAlgorithm]] ~SET %closeAlgorithm, .[[abortAlgorithm]] ~SET %abortAlgorithm ◎ Set controller.[[started]] to false. ◎ Set controller.[[strategySizeAlgorithm]] to sizeAlgorithm. ◎ Set controller.[[strategyHWM]] to highWaterMark. ◎ Set controller.[[writeAlgorithm]] to writeAlgorithm. ◎ Set controller.[[closeAlgorithm]] to closeAlgorithm. ◎ Set controller.[[abortAlgorithm]] to abortAlgorithm.
- %backpressure ~LET ! `WritableStreamDefaultControllerGetBackpressure$A( %controller ) ◎ Let backpressure be ! WritableStreamDefaultControllerGetBackpressure(controller).
- ! `WritableStreamUpdateBackpressure$A( %stream, %backpressure ) ◎ Perform ! WritableStreamUpdateBackpressure(stream, backpressure).
- %startResult ~LET 次を遂行した結果(例外を投出し得る) ⇒ %startAlgorithm() ◎ Let startResult be the result of performing startAlgorithm. (This may throw an exception.)
-
%startPromise ~LET %startResult で`解決される~promise$ ◎ Let startPromise be a promise resolved with startResult.
-
%startPromise の`充足-時$には: ◎ Upon fulfillment of startPromise,
- ~Assert: %stream.[[state]] ~IN { `writable^l, `erroring^l } ◎ Assert: stream.[[state]] is "writable" or "erroring".
- %controller.[[started]] ~SET ~true ◎ Set controller.[[started]] to true.
- ! `WritableStreamDefaultControllerAdvanceQueueIfNeeded$A( %controller ) ◎ Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).
-
事由 %r による %startPromise の`却下-時$には: ◎ Upon rejection of startPromise with reason r,
- ~Assert: %stream.[[state]] ~IN { `writable^l, `erroring^l } ◎ Assert: stream.[[state]] is "writable" or "erroring".
- %controller.[[started]] ~SET ~true ◎ Set controller.[[started]] to true.
- ! `WritableStreamDealWithRejection$A( %stream, %r ) ◎ Perform ! WritableStreamDealWithRejection(stream, r).
-
4.8.3. `SetUpWritableStreamDefaultControllerFromUnderlyingSink( stream, underlyingSink, highWaterMark, sizeAlgorithm )^A
- ~Assert: %underlyingSink ~NEQ ~undefined ◎ Assert: underlyingSink is not undefined.
- %controller ~LET `ObjectCreate$A( `WritableStreamDefaultController$C の `prototype^c ~propの元の値 ) ◎ Let controller be ObjectCreate(the original value of WritableStreamDefaultController's prototype property).
-
%startAlgorithm ~LET 次を走らす手続き: ◎ Let startAlgorithm be the following steps:
- ~RET ? `InvokeOrNoop$A( %underlyingSink, `start^l, « %controller » ) ◎ Return ? InvokeOrNoop(underlyingSink, "start", « controller »).
- %writeAlgorithm ~LET ? `CreateAlgorithmFromUnderlyingMethod$A( %underlyingSink, `write^l, `1^b, « %controller » ) ◎ Let writeAlgorithm be ? CreateAlgorithmFromUnderlyingMethod(underlyingSink, "write", 1, « controller »).
- %closeAlgorithm ~LET ? `CreateAlgorithmFromUnderlyingMethod$A( %underlyingSink, `close^l, `0^b, « » ) ◎ Let closeAlgorithm be ? CreateAlgorithmFromUnderlyingMethod(underlyingSink, "close", 0, « »).
- %abortAlgorithm ~LET ? `CreateAlgorithmFromUnderlyingMethod$A( %underlyingSink, `abort^l, `1^b, « » ) ◎ Let abortAlgorithm be ? CreateAlgorithmFromUnderlyingMethod(underlyingSink, "abort", 1, « »).
- ? `SetUpWritableStreamDefaultController$A( %stream, %controller, %startAlgorithm, %writeAlgorithm, %closeAlgorithm, %abortAlgorithm, %highWaterMark, %sizeAlgorithm ) ◎ Perform ? SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm).
4.8.4. `WritableStreamDefaultControllerClearAlgorithms( controller )^A
この抽象~演算は,~streamが~closeされるか~errorしたときに~callされ、各種~algoへの参照を除去することにより,それ以降は それらが実行されないようにする。 その結果、`下層~槽$( `WritableStream$C ~obj)自身が — まだ参照されていても — ~garbage収集されることを許可する。 ◎ This abstract operation is called once the stream is closed or errored and the algorithms will not be executed any more. By removing the algorithm references it permits the underlying sink object to be garbage collected even if the WritableStream itself is still referenced.
この~algoの結果は,現在は観測-可能でないが、~JSに 弱い参照が追加されたなら,そうなり得る。 追加されなくとも、実装は,類似する手続きを含めたいと求めるであろう。 ◎ The results of this algorithm are not currently observable, but could become so if JavaScript eventually adds weak references. But even without that factor, implementations will likely want to include similar steps.
一部の~~際どい事例では、この演算は,複数回 遂行されることになるが、 2 回目~以降は何もしない。 ◎ This operation will be performed multiple times in some edge cases. After the first time it will do nothing.
- %controller.[[writeAlgorithm]] ~SET ~undefined ◎ Set controller.[[writeAlgorithm]] to undefined.
- %controller.[[closeAlgorithm]] ~SET ~undefined ◎ Set controller.[[closeAlgorithm]] to undefined.
- %controller.[[abortAlgorithm]] ~SET ~undefined ◎ Set controller.[[abortAlgorithm]] to undefined.
4.8.5. `WritableStreamDefaultControllerClose( controller )^A
- ! `EnqueueValueWithSize$A( %controller, `close^l, `0^b ) ◎ Perform ! EnqueueValueWithSize(controller, "close", 0).
- ! `WritableStreamDefaultControllerAdvanceQueueIfNeeded$A( %controller ) ◎ Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).
4.8.6. `WritableStreamDefaultControllerGetChunkSize( controller, chunk )^A
- %returnValue ~LET 次を遂行した結果を~ECMAScript完了~値に解釈した結果 ⇒ %controller.[[strategySizeAlgorithm]]( %chunk ) ◎ Let returnValue be the result of performing controller.[[strategySizeAlgorithm]], passing in chunk, and interpreting the result as an ECMAScript completion value.
-
~IF[ %returnValue は`中途完了$である ]: ◎ If returnValue is an abrupt completion,
- ! `WritableStreamDefaultControllerErrorIfNeeded$A( %controller, %returnValue.[[Value]] ) ◎ Perform ! WritableStreamDefaultControllerErrorIfNeeded(controller, returnValue.[[Value]]).
- ~RET `1^b ◎ Return 1.
- ~RET %returnValue.[[Value]] ◎ Return returnValue.[[Value]].
4.8.7. `WritableStreamDefaultControllerGetDesiredSize( controller )^A
- ~RET %controller.[[strategyHWM]] − %controller.[[queueTotalSize]] ◎ Return controller.[[strategyHWM]] − controller.[[queueTotalSize]].
4.8.8. `WritableStreamDefaultControllerWrite( controller, chunk, chunkSize )^A
- %writeRecord ~LET `~Record$ { [[chunk]]: %chunk } ◎ Let writeRecord be Record {[[chunk]]: chunk}.
- %enqueueResult ~LET `EnqueueValueWithSize$A( %controller, %writeRecord, %chunkSize ) ◎ Let enqueueResult be EnqueueValueWithSize(controller, writeRecord, chunkSize).
-
~IF[ %enqueueResult は`中途完了$である ]: ◎ If enqueueResult is an abrupt completion,
- ! `WritableStreamDefaultControllerErrorIfNeeded$A( %controller, %enqueueResult.[[Value]] ) ◎ Perform ! WritableStreamDefaultControllerErrorIfNeeded(controller, enqueueResult.[[Value]]).
- ~RET ◎ Return.
- %stream ~LET %controller.[[controlledWritableStream]] ◎ Let stream be controller.[[controlledWritableStream]].
-
~IF[ ! `WritableStreamCloseQueuedOrInFlight$A( %stream ) ~EQ ~false ]~AND[ %stream.[[state]] ~EQ `writable^l ] : ◎ If ! WritableStreamCloseQueuedOrInFlight(stream) is false and stream.[[state]] is "writable",
- %backpressure ~LET ! `WritableStreamDefaultControllerGetBackpressure$A( %controller ) ◎ Let backpressure be ! WritableStreamDefaultControllerGetBackpressure(controller).
- ! `WritableStreamUpdateBackpressure$A( %stream, %backpressure ) ◎ Perform ! WritableStreamUpdateBackpressure(stream, backpressure).
- ! `WritableStreamDefaultControllerAdvanceQueueIfNeeded$A( %controller ) ◎ Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).
4.8.9. `WritableStreamDefaultControllerAdvanceQueueIfNeeded( controller )^A
- %stream ~LET %controller.[[controlledWritableStream]] ◎ Let stream be controller.[[controlledWritableStream]].
- ~IF[ %controller.[[started]] ~EQ ~false ] ⇒ ~RET ◎ If controller.[[started]] is false, return.
- ~IF[ %stream.[[inFlightWriteRequest]] ~NEQ ~undefined ] ⇒ ~RET ◎ If stream.[[inFlightWriteRequest]] is not undefined, return.
- %state ~LET %stream.[[state]] ◎ Let state be stream.[[state]].
- ~IF[ %state ~IN { `closed^l, `errored^l } ] ⇒ ~RET ◎ If state is "closed" or "errored", return.
-
~IF[ %state ~EQ `erroring^l ]: ◎ If state is "erroring",
- ! `WritableStreamFinishErroring$A( %stream ) ◎ Perform ! WritableStreamFinishErroring(stream).
- ~RET ◎ Return.
- ~IF[ %controller.[[queue]] は空である ] ⇒ ~RET ◎ If controller.[[queue]] is empty, return.
- %writeRecord ~LET ! `PeekQueueValue$A( %controller ) ◎ Let writeRecord be ! PeekQueueValue(controller).
- ~IF[ %writeRecord ~EQ `close^l ] ⇒ ! `WritableStreamDefaultControllerProcessClose$A( %controller ) ◎ If writeRecord is "close", perform ! WritableStreamDefaultControllerProcessClose(controller).
- ~ELSE ⇒ ! `WritableStreamDefaultControllerProcessWrite$A( %controller, %writeRecord.[[chunk]] ) ◎ Otherwise, perform ! WritableStreamDefaultControllerProcessWrite(controller, writeRecord.[[chunk]]).
4.8.10. `WritableStreamDefaultControllerErrorIfNeeded( controller, error )^A
- ~IF[ %controller.[[controlledWritableStream]].[[state]] ~EQ `writable^l ] ⇒ ! `WritableStreamDefaultControllerError$A( %controller, %error ) ◎ If controller.[[controlledWritableStream]].[[state]] is "writable", perform ! WritableStreamDefaultControllerError(controller, error).
4.8.11. `WritableStreamDefaultControllerProcessClose( controller )^A
- %stream ~LET %controller.[[controlledWritableStream]] ◎ Let stream be controller.[[controlledWritableStream]].
- ! `WritableStreamMarkCloseRequestInFlight$A( %stream ) ◎ Perform ! WritableStreamMarkCloseRequestInFlight(stream).
- ! `DequeueValue$A( %controller ) ◎ Perform ! DequeueValue(controller).
- ~Assert: %controller.[[queue]] は空である ◎ Assert: controller.[[queue]] is empty.
- %sinkClosePromise ~LET 次を遂行した結果 ⇒ %controller.[[closeAlgorithm]]() ◎ Let sinkClosePromise be the result of performing controller.[[closeAlgorithm]].
- ! `WritableStreamDefaultControllerClearAlgorithms$A( %controller ) ◎ Perform ! WritableStreamDefaultControllerClearAlgorithms(controller).
-
-
%sinkClosePromise の`充足-時$には: ◎ Upon fulfillment of sinkClosePromise,
- ! `WritableStreamFinishInFlightClose$A( %stream ) ◎ Perform ! WritableStreamFinishInFlightClose(stream).
-
事由 %reason による %sinkClosePromise の`却下-時$には: ◎ Upon rejection of sinkClosePromise with reason reason,
- ! `WritableStreamFinishInFlightCloseWithError$A( %stream, %reason ) ◎ Perform ! WritableStreamFinishInFlightCloseWithError(stream, reason).
-
4.8.12. `WritableStreamDefaultControllerProcessWrite( controller, chunk )^A
- %stream ~LET %controller.[[controlledWritableStream]] ◎ Let stream be controller.[[controlledWritableStream]].
- ! `WritableStreamMarkFirstWriteRequestInFlight$A( %stream ) ◎ Perform ! WritableStreamMarkFirstWriteRequestInFlight(stream).
-
%sinkWritePromise ~LET 次を遂行した結果 ⇒ %controller.[[writeAlgorithm]]( %chunk ) ◎ Let sinkWritePromise be the result of performing controller.[[writeAlgorithm]], passing in chunk.
-
%sinkWritePromise の`充足-時$には: ◎ Upon fulfillment of sinkWritePromise,
- ! `WritableStreamFinishInFlightWrite$A( %stream ) ◎ Perform ! WritableStreamFinishInFlightWrite(stream).
- %state ~LET %stream.[[state]] ◎ Let state be stream.[[state]].
- ~Assert: %state ~IN { `writable^l, `erroring^l } ◎ Assert: state is "writable" or "erroring".
- ! `DequeueValue$A( %controller ) ◎ Perform ! DequeueValue(controller).
-
~IF[ ! `WritableStreamCloseQueuedOrInFlight$A(stream) ~EQ ~false ]~AND[ %state ~EQ `writable^l ]: ◎ If ! WritableStreamCloseQueuedOrInFlight(stream) is false and state is "writable",
- %backpressure ~LET ! `WritableStreamDefaultControllerGetBackpressure$A( %controller ) ◎ Let backpressure be ! WritableStreamDefaultControllerGetBackpressure(controller).
- ! `WritableStreamUpdateBackpressure$A( %stream, %backpressure ) ◎ Perform ! WritableStreamUpdateBackpressure(stream, backpressure).
- ! `WritableStreamDefaultControllerAdvanceQueueIfNeeded$A( %controller ) ◎ Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).
-
事由 %reason による %sinkWritePromise の`却下-時$には: ◎ Upon rejection of sinkWritePromise with reason,
- ~IF[ %stream.[[state]] ~EQ `writable^l ] ⇒ ! `WritableStreamDefaultControllerClearAlgorithms$A( %controller ) ◎ If stream.[[state]] is "writable", perform ! WritableStreamDefaultControllerClearAlgorithms(controller).
- ! `WritableStreamFinishInFlightWriteWithError$A( %stream, %reason ) ◎ Perform ! WritableStreamFinishInFlightWriteWithError(stream, reason).
-
4.8.13. `WritableStreamDefaultControllerGetBackpressure( controller )^A
- %desiredSize ~LET ! `WritableStreamDefaultControllerGetDesiredSize$A( %controller ) ◎ Let desiredSize be ! WritableStreamDefaultControllerGetDesiredSize(controller).
- ~RET 次が満たされるならば ~true / ~ELSE_ ~false ⇒ %desiredSize ~LTE `0^b ◎ Return desiredSize ≤ 0.
4.8.14. `WritableStreamDefaultControllerError( controller, error )^A
- %stream ~LET %controller.[[controlledWritableStream]] ◎ Let stream be controller.[[controlledWritableStream]].
- ~Assert: %stream.[[state]] ~EQ `writable^l ◎ Assert: stream.[[state]] is "writable".
- ! `WritableStreamDefaultControllerClearAlgorithms$A( %controller ) ◎ Perform ! WritableStreamDefaultControllerClearAlgorithms(controller).
- ! `WritableStreamStartErroring$A( %stream, %error ) ◎ Perform ! WritableStreamStartErroring(stream, error).
5. 形式変換~stream
5.1. 形式変換~streamの利用-法
形式変換~streamを利用する自然な仕方は、それを`可読~stream$と`可書~stream$の間の`~pipe$に置くことである。 `可読~stream$から`可書~stream$へ旅する`~chunk$たちは、形式変換~streamを通過する際に形式変換されることになる。 `背圧$は尊重されるので、形式変換して消費できるより高速に~dataが読取されることはない。 ◎ The natural way to use a transform stream is to place it in a pipe between a readable stream and a writable stream. Chunks that travel from the readable stream to the writable stream will be transformed as they pass through the transform stream. Backpressure is respected, so data will not be read faster than it can be transformed and consumed.
%readableStream .pipeThrough(%transformStream) .pipeTo(%writableStream) .then(() => console.log(`すべての~dataは成功裡に形式変換されました^l)) .catch(%e => console.error(`何かまずいことが起きたようです^l, %e));
形式変換~streamの[ `readable$ts / `writable$ts ]~propを利用すれば、[ `可読~stream$ / `可書~stream$ ]を成す通例的な~interfaceに直に~accessできる。 この例では、~streamの`書込器$~interfaceを利用して,`可書~側$に~dataを給してから、`可読~側$を %anotherWritableStream に~pipeする。 ◎ You can also use the readable and writable properties of a transform stream directly to access the usual interfaces of a readable stream and writable stream. In this example we supply data to the writable side of the stream using its writer interface. The readable side is then piped to anotherWritableStream.
const %writer = %transformStream.writable.getWriter(); %writer.write(`input chunk^l); %transformStream.readable.pipeTo(%anotherWritableStream);
`~identity形式変換~stream$には、可読~streamと可書~streamとの間を容易に変換する利用がある。 例えば `fetch()$m ~APIは、`要請~本体$を可読~streamとして受容するが、 可書~stream~interfaceを介して~upload用の~dataを書込できれば,もっと簡便になる。 ~identity形式変換~streamは、これに取組む: ◎ One use of identity transform streams is to easily convert between readable and writable streams. For example, the fetch() API accepts a readable stream request body, but it can be more convenient to write data for uploading via a writable stream interface. Using an identity transform stream addresses this:
const { %writable, %readable } = new TransformStream(); fetch(`...^l, { body: %readable }).then(%response => /* ... */); const %writer = %writable.getWriter(); %writer.write(new Uint8Array([0x73, 0x74, 0x72, 0x65, 0x61, 0x6D, 0x73, 0x21])); %writer.close();
~identity形式変換~streamの別の利用は、追加の~bufferingを`~pipe$に追加することである。 この例では、 %readableStream と %writableStream の間に余分の~bufferingを追加する。 ◎ Another use of identity transform streams is to add additional buffering to a pipe. In this example we add extra buffering between readableStream and writableStream.
const %writableStrategy = new ByteLengthQueuingStrategy({ highWaterMark: 1024 * 1024 }); %readableStream .pipeThrough(new TransformStream(undefined, %writableStrategy)) .pipeTo(%writableStream);
5.2. ~class `TransformStream^C
5.2.1. ~class定義
~INFORMATIVE`TransformStream$C ~classは、 `ECMASCRIPT$r 風の構文で書くならば,次のようになる: ◎ If one were to write the TransformStream class in something close to the syntax of [ECMASCRIPT], it would look like
class TransformStream { `constructor$ts(%transformer = {}, %writableStrategy = {}, %readableStrategy = {}) get `readable()$ts get `writable()$ts }
5.2.2. 内部~slot
`TransformStream$C の各~instanceは、次の一覧に述べる各種 内部~slotを伴って作成される: ◎ Instances of TransformStream are created with the internal slots described in the following table:
内部~slot | 説明0(参考) |
---|---|
[[backpressure]] | 最後に観測された時点で [[readable]] 上に背圧があったかどうか。 ◎ Whether there was backpressure on [[readable]] the last time it was observed |
[[backpressureChangePromise]] | [[backpressure]] の値が変更されるたびに,充足され, 置換される~promise。 ◎ A promise which is fulfilled and replaced every time the value of [[backpressure]] changes |
[[readable]] | この~objにより制御される `ReadableStream$C ~instance ◎ The ReadableStream instance controlled by this object |
[[transformStreamController]] | [[readable]], [[writable]] を制御する能を伴って作成される `TransformStreamDefaultController$C 。 `IsTransformStream$A による~brand検査-時にも利用される。 ◎ A TransformStreamDefaultController created with the ability to control [[readable]] and [[writable]]; also used for the IsTransformStream brand check |
[[writable]] | この~objにより制御される `WritableStream$C ~instance ◎ The WritableStream instance controlled by this object |
5.2.3. `new TransformStream( transformer = {}, writableStrategy = {}, readableStrategy = {} )^ts
%transformer 引数は — `§形式変換器~API$にて述べるように — `形式変換器$を表現する。 ◎ The transformer argument represents the transformer, as described in §5.2.4 Transformer API.
[ %writableStrategy / %readableStrategy ]引数は[ 可書~側/可読~側 ]用の`~queuing策$~objを与える。 これらは,[ `WritableStream$C / `ReadableStream$C ]~obj(同順)の構築に利用され、[[ 形式変換nを円滑に変速したり, `~pipe$内に~bufferする量を増やす ]ために, `TransformStream$C に~bufferingを追加する ]ときにも利用され得る。 それぞれ,供されなかった場合の既定の挙動は、`限界水位$[ 1 / 0 ](同順)にされた `CountQueuingStrategy$C と同じになる。 ◎ The writableStrategy and readableStrategy arguments are the queuing strategy objects for the writable and readable sides respectively. These are used in the construction of the WritableStream and ReadableStream objects and can be used to add buffering to a TransformStream, in order to smooth out variations in the speed of the transformation, or to increase the amount of buffering in a pipe. If they are not provided, the default behavior will be the same as a CountQueuingStrategy, with respective high water marks of 1 and 0.
- %writableSizeFunction ~LET ? `GetV$A( %writableStrategy, `size^l ) ◎ Let writableSizeFunction be ? GetV(writableStrategy, "size").
- %writableHighWaterMark ~LET ? `GetV$A( %writableStrategy, `highWaterMark^l ) ◎ Let writableHighWaterMark be ? GetV(writableStrategy, "highWaterMark").
- %readableSizeFunction ~LET ? `GetV$A( %readableStrategy, `size^l ) ◎ Let readableSizeFunction be ? GetV(readableStrategy, "size").
- %readableHighWaterMark ~LET ? `GetV$A( %readableStrategy, `highWaterMark^l ) ◎ Let readableHighWaterMark be ? GetV(readableStrategy, "highWaterMark").
- %writableType ~LET ? `GetV$A( %transformer, `writableType^l ) ◎ Let writableType be ? GetV(transformer, "writableType").
- ~IF[ %writableType ~NEQ ~undefined ] ⇒ ~THROW `RangeError^b ◎ If writableType is not undefined, throw a RangeError exception.
- %writableSizeAlgorithm ~LET ? `MakeSizeAlgorithmFromSizeFunction$A( %writableSizeFunction ) ◎ Let writableSizeAlgorithm be ? MakeSizeAlgorithmFromSizeFunction(writableSizeFunction).
- ~IF[ %writableHighWaterMark ~EQ ~undefined ] ⇒ %writableHighWaterMark ~SET `1^b ◎ If writableHighWaterMark is undefined, set writableHighWaterMark to 1.
- %writableHighWaterMark ~SET ? `ValidateAndNormalizeHighWaterMark$A( %writableHighWaterMark ) ◎ Set writableHighWaterMark to ? ValidateAndNormalizeHighWaterMark(writableHighWaterMark).
- %readableType ~LET ? `GetV$A( %transformer, `readableType^l ) ◎ Let readableType be ? GetV(transformer, "readableType").
- ~IF[ %readableType ~NEQ ~undefined ] ⇒ ~THROW `RangeError^b ◎ If readableType is not undefined, throw a RangeError exception.
- %readableSizeAlgorithm ~LET ? `MakeSizeAlgorithmFromSizeFunction$A( %readableSizeFunction ) ◎ Let readableSizeAlgorithm be ? MakeSizeAlgorithmFromSizeFunction(readableSizeFunction).
- ~IF[ %readableHighWaterMark ~EQ ~undefined ] ⇒ %readableHighWaterMark ~SET `0^b ◎ If readableHighWaterMark is undefined, set readableHighWaterMark to 0.
- %readableHighWaterMark ~SET ? `ValidateAndNormalizeHighWaterMark$A( %readableHighWaterMark ) ◎ Set readableHighWaterMark be ? ValidateAndNormalizeHighWaterMark(readableHighWaterMark).
- %startPromise ~LET `新たな~promise$ ◎ Let startPromise be a new promise.
- ! `InitializeTransformStream$A( ~this, %startPromise, %writableHighWaterMark, %writableSizeAlgorithm, %readableHighWaterMark, %readableSizeAlgorithm ) ◎ Perform ! InitializeTransformStream(this, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm).
- ? `SetUpTransformStreamDefaultControllerFromTransformer$A( ~this, %transformer ) ◎ Perform ? SetUpTransformStreamDefaultControllerFromTransformer(this, transformer).
- %startResult ~LET ? `InvokeOrNoop$A( %transformer, `start^l, « ~this.[[transformStreamController]] » ) ◎ Let startResult be ? InvokeOrNoop(transformer, "start", « this.[[transformStreamController]] »).
- %startResult で %startPromise を`解決する$ ◎ Resolve startPromise with startResult.
5.2.4. 形式変換器~API
~INFORMATIVE`TransformStream()$ts 構築子は、 1 個目の引数に[ `形式変換器$を表現している~JS~obj ]を受容する。 そのような~objには、次に挙げる~methodを包含させられる: ◎ The TransformStream() constructor accepts as its first argument a JavaScript object representing the transformer. Such objects can contain any of the following methods:
- `start(controller)@tf
- この関数は、 `TransformStream$C を作成する間に即時に~callされる。 ◎ A function that is called immediately during creation of the TransformStream.
- これは概して、[ %controller.`enqueue()$tsdc を利用して,接頭-`~chunk$を~enqueueする ]ために利用される。 それらの~chunkは、`可読~側$から読取されるが,`可書~側$へのどの書込にも依存しないことになる。 ◎ Typically this is used to enqueue prefix chunks, using controller.enqueue(). Those chunks will be read from the readable side but don’t depend on any writes to the writable side.
- この処理が非同期的になる場合 — 例えば、接頭-~chunkたちを獲得するのに 多少の労が~~要るために — この関数は,成否を合図する~promiseを返すようにすることもできる。 却下される~promiseは、~streamを~errorにすることになる。 投出された例外は、 `TransformStream()$ts 構築子により再~投出されることになる。 ◎ If this initial process is asynchronous, for example because it takes some effort to acquire the prefix chunks, the function can return a promise to signal success or failure; a rejected promise will error the stream. Any thrown exceptions will be re-thrown by the TransformStream() constructor.
- `transform(chunk, controller)@tf
- この関数は、[ 元々は`可書~側$に書込された新たな`~chunk$が,形式変換~用に準備済みになった ]とき,~callされる。 ~stream実装は、この関数が~callされるのは,以前の形式変換が成功した後に限られ, かつ[ `start()$snk が完了する前 / `flush()$tf ~callされた後 ]には決してならないことを保証する。 ◎ A function called when a new chunk originally written to the writable side is ready to be transformed. The stream implementation guarantees that this function will be called only after previous transforms have succeeded, and never before start() has completed or after flush() has been called.
- この関数は、形式変換~streamにおける実際の形式変換n作業を遂行する。 その結果は、 %controller.`enqueue()$tsdc を利用して,~enqueueできる。 ここでは、[ 可書~側に 1 個の~chunkが書込されたときの結果が,`可読~側$では 0 個または複数個の~chunkになる ]ことも許可される — %controller.`enqueue()$tsdc が何回~callされたかに依存して。 `§~template内の~tagを置換する形式変換~stream$では、ときどき 0 個の~chunkを~enqueueして,これを例示している。 ◎ This function performs the actual transformation work of the transform stream. It can enqueue the results using controller.enqueue(). This permits a single chunk written to the writable side to result in zero or multiple chunks on the readable side, depending on how many times controller.enqueue() is called. §8.9 A transform stream that replaces template tags demonstrates this by sometimes enqueuing zero chunks.
- 形式変換~処理が非同期的になる場合、この関数は,形式変換nの成否を合図する~promiseを返すようにすることもできる。 却下される~promiseは、形式変換~streamの可読~側, 可書~側 両方を~errorにすることになる。 ◎ If the process of transforming is asynchronous, this function can return a promise to signal success or failure of the transformation. A rejected promise will error both the readable and writable sides of the transform stream.
- `transform()$tf が給されなかった場合、~identity形式変換が利用される — それは、可書~側からの~chunkをそのまま可読~側に~enqueueする。 ◎ If no transform() is supplied, the identity transform is used, which enqueues chunks unchanged from the writable side to the readable side.
- `flush(controller)@tf
- この関数は、[ `可書~側$にすべての`~chunk$が書込され, `transform()$tf を成功裡に通過して形式変換された後,可書~側が~closeされつつある ]とき,~callされる。 ◎ A function called after all chunks written to the writable side have been transformed by successfully passing through transform(), and the writable side is about to be closed.
- これは概して、`可読~側$に — それも~closeされる前に — 接尾-~chunkたちを~enqueueするために利用される。 その例は、`§~template内の~tagを置換する形式変換~stream$に見れる。 ◎ Typically this is used to enqueue suffix chunks to the readable side, before that too becomes closed. An example can be seen in §8.9 A transform stream that replaces template tags.
- この書出し処理が非同期的になる場合、この関数は,成否を合図する~promiseを返すようにすることもできる — その結果は、 %stream.`writable$ts.`write()$dw の~call元へ通信されることになる。 加えて,却下される~promiseは、可読~側, 可書~側の両~streamとも~errorにすることになる。 例外を投出した場合、却下される~promiseを返すのと同じに扱われる。 ◎ If the flushing process is asynchronous, the function can return a promise to signal success or failure; the result will be communicated to the caller of stream.writable.write(). Additionally, a rejected promise will error both the readable and writable sides of the stream. Throwing an exception is treated the same as returning a rejected promise.
- ( `flush()$tf の内側で %controller.`terminate()$tsdc を~callする必要は無いことに注意。 ~streamは,すでに成功裡に~closeし終える処理にあり、それを終了するのは非生産的になる)。 ◎ (Note that there is no need to call controller.terminate() inside flush(); the stream is already in the process of successfully closing down, and terminating it would be counterproductive.)
[ `start()$tf / `transform()$tf / `flush()$tf ]に渡される %controller ~objは、 `TransformStreamDefaultController$C の~instanceであり,次の能を備える ⇒# `~chunk$を`可読~側$に~enqueueする, ~streamを終了する, ~streamを~errorにする ◎ The controller object passed to start(), transform(), and flush() is an instance of TransformStreamDefaultController, and has the ability to enqueue chunks to the readable side, or to terminate or error the stream.
5.2.5. `TransformStream$C ~prototypeの~prop
5.2.5.1. `get readable^ts
`readable^c 取得子は、形式変換~streamの`可読~側$への~accessを与える。 ◎ The readable getter gives access to the readable side of the transform stream.
- ~IF[ ! `IsTransformStream$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsTransformStream(this) is false, throw a TypeError exception.
- ~RET ~this.[[readable]] ◎ Return this.[[readable]].
5.2.5.2. `get writable^ts
`writable^c 取得子は、形式変換~streamの`可書~側$への~accessを与える。 ◎ The writable getter gives access to the writable side of the transform stream.
- ~IF[ ! `IsTransformStream$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsTransformStream(this) is false, throw a TypeError exception.
- ~RET ~this.[[writable]] ◎ Return this.[[writable]].
5.3. 一般の形式変換~stream抽象~演算
5.3.1. `CreateTransformStream( startAlgorithm, transformAlgorithm, flushAlgorithm [, writableHighWaterMark [, writableSizeAlgorithm [, readableHighWaterMark [, readableSizeAlgorithm ] ] ] ] )^A
この抽象~演算は、 `TransformStream$C ~instanceを作成したいと望むような,他の仕様から~callされる用途に意味されている。
- [ %transformAlgorithm / %flushAlgorithm ]は、~promiseを返す~algoで~MUST。
- [ %writableHighWaterMark / %readableHighWaterMark ]は、給されるならば,負でも `NaN^b でもない ~numberで~MUST。
- [ %writableSizeAlgorithm / %readableSizeAlgorithm ]は、給されるならば,`~chunk$~objを受容して ~numberを返す~algoで~MUST。
注記: `CreateTransformStream$A は、給された %startAlgorithm が投出するとき, そのときに限り例外を投出する。 ◎ CreateTransformStream throws an exception if and only if the supplied startAlgorithm throws.
- ~IF[ %writableHighWaterMark は渡されていない ] ⇒ %writableHighWaterMark ~SET `1^b ◎ If writableHighWaterMark was not passed, set it to 1.
- ~IF[ %writableSizeAlgorithm は渡されていない ] ⇒ %writableSizeAlgorithm ~SET `1^b を返す~algo ◎ If writableSizeAlgorithm was not passed, set it to an algorithm that returns 1.
- ~IF[ %readableHighWaterMark は渡されていない ] ⇒ %readableHighWaterMark~SET `0^b ◎ If readableHighWaterMark was not passed, set it to 0.
- ~IF[ %readableSizeAlgorithm は渡されていない ] ⇒ %readableSizeAlgorithm~SET `1^b を返す~algo ◎ If readableSizeAlgorithm was not passed, set it to an algorithm that returns 1.
- ~Assert: ! `IsNonNegativeNumber$A( %writableHighWaterMark ) ~EQ ~true ◎ Assert: ! IsNonNegativeNumber(writableHighWaterMark) is true.
- ~Assert: ! `IsNonNegativeNumber$A( %readableHighWaterMark ) ~EQ ~true ◎ Assert: ! IsNonNegativeNumber(readableHighWaterMark) is true.
- %stream ~LET `ObjectCreate$A( `TransformStream$C の `prototype^c ~propの元の値 ) ◎ Let stream be ObjectCreate(the original value of TransformStream's prototype property).
- %startPromise ~LET `新たな~promise$ ◎ Let startPromise be a new promise.
- ! `InitializeTransformStream$A( %stream, %startPromise, %writableHighWaterMark, %writableSizeAlgorithm, %readableHighWaterMark, %readableSizeAlgorithm ) ◎ Perform ! InitializeTransformStream(stream, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm).
- %controller ~LET `ObjectCreate$A( `TransformStreamDefaultController$C の `prototype^c ~propの元の値 ) ◎ Let controller be ObjectCreate(the original value of TransformStreamDefaultController's prototype property).
- ! `SetUpTransformStreamDefaultController$A( %stream, %controller, %transformAlgorithm, %flushAlgorithm ) ◎ Perform ! SetUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm).
- %startResult ~LET 次を遂行した結果(例外を投出し得る) ⇒ %startAlgorithm() ◎ Let startResult be the result of performing startAlgorithm. (This may throw an exception.)
- %startResult で %startPromise を`解決する$ ◎ Resolve startPromise with startResult.
- ~RET %stream ◎ Return stream.
5.3.2. `InitializeTransformStream( stream, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm )^A
- %startAlgorithm ~LET %startPromise を返す~algo ◎ Let startAlgorithm be an algorithm that returns startPromise.
-
%writeAlgorithm ~LET 引数 ( %chunk ) をとり,次を走らす手続き: ◎ Let writeAlgorithm be the following steps, taking a chunk argument:
- ~RET ! `TransformStreamDefaultSinkWriteAlgorithm$A( %stream, %chunk ) ◎ Return ! TransformStreamDefaultSinkWriteAlgorithm(stream, chunk).
-
%abortAlgorithm ~LET 引数 ( %reason ) をとり,次を走らす手続き: ◎ Let abortAlgorithm be the following steps, taking a reason argument:
- ~RET ! `TransformStreamDefaultSinkAbortAlgorithm$A( %stream, %reason ) ◎ Return ! TransformStreamDefaultSinkAbortAlgorithm(stream, reason).
-
%closeAlgorithm ~LET 次を走らす手続き: ◎ Let closeAlgorithm be the following steps:
- ~RET ! `TransformStreamDefaultSinkCloseAlgorithm$A( %stream ) ◎ Return ! TransformStreamDefaultSinkCloseAlgorithm(stream).
- %stream.[[writable]] ~SET ! `CreateWritableStream$A( %startAlgorithm, %writeAlgorithm, %closeAlgorithm, %abortAlgorithm, %writableHighWaterMark, %writableSizeAlgorithm ) ◎ Set stream.[[writable]] to ! CreateWritableStream(startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, writableHighWaterMark, writableSizeAlgorithm).
-
%pullAlgorithm ~LET 次を走らす手続き: ◎ Let pullAlgorithm be the following steps:
- ~RET ! `TransformStreamDefaultSourcePullAlgorithm$A( %stream ) ◎ Return ! TransformStreamDefaultSourcePullAlgorithm(stream).
-
%cancelAlgorithm ~LET 引数 ( %reason ) をとり,次を走らす手続き: ◎ Let cancelAlgorithm be the following steps, taking a reason argument:
- ! `TransformStreamErrorWritableAndUnblockWrite$A( %stream, %reason ) ◎ Perform ! TransformStreamErrorWritableAndUnblockWrite(stream, reason).
- ~RET ~undefined で`解決される~promise$ ◎ Return a promise resolved with undefined.
- %stream.[[readable]] ~SET ! `CreateReadableStream$A( %startAlgorithm, %pullAlgorithm, %cancelAlgorithm, %readableHighWaterMark, %readableSizeAlgorithm ) ◎ Set stream.[[readable]] to ! CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm, readableHighWaterMark, readableSizeAlgorithm).
-
%stream の ⇒# .[[backpressure]] ~SET ~undefined, .[[backpressureChangePromise]] ~SET ~undefined ◎ Set stream.[[backpressure]] and stream.[[backpressureChangePromise]] to undefined.
注記: [[backpressure]] ~slotは、 `TransformStreamSetBackpressure$A により初期化できるよう, ~undefined に設定される。 別法として,実装は、 [[backpressure]] 用に厳格な真偽~値を利用して,初期化される仕方を変更できる。 これは、初期化が[ %transformer の `start()$tf ~methodが~callされる前 ]に正しく完了される限り,利用者~codeからは可視にならない。 ◎ The [[backpressure]] slot is set to undefined so that it can be initialized by TransformStreamSetBackpressure. Alternatively, implementations can use a strictly boolean value for [[backpressure]] and change the way it is initialized. This will not be visible to user code so long as the initialization is correctly completed before transformer’s start() method is called.
- ! `TransformStreamSetBackpressure$A( %stream, ~true ) ◎ Perform ! TransformStreamSetBackpressure(stream, true).
- %stream.[[transformStreamController]] ~SET ~undefined ◎ Set stream.[[transformStreamController]] to undefined.
5.3.3. `IsTransformStream( x )^A
- ~IF[ `Type$A( %x ) ~NEQ `Object^b ] ⇒ ~RET ~false ◎ If Type(x) is not Object, return false.
- ~IF[ %x は [[transformStreamController]] 内部~slotを持たない ] ⇒ ~RET ~false ◎ If x does not have a [[transformStreamController]] internal slot, return false.
- ~RET ~true ◎ Return true.
5.3.4. `TransformStreamError( stream, e )^A
- ! `ReadableStreamDefaultControllerError$A( %stream.[[readable]].[[readableStreamController]], %e ) ◎ Perform ! ReadableStreamDefaultControllerError(stream.[[readable]].[[readableStreamController]], e).
- ! `TransformStreamErrorWritableAndUnblockWrite$A( %stream, %e ) ◎ Perform ! TransformStreamErrorWritableAndUnblockWrite(stream, e).
注記: この演算は、両方/片方の側が すでに~errorしたときは,正しく働く。 結果として,~call~~元~algoは、~error条件に応答するときに~stream状態を検査する必要がなくなる。 ◎ This operation works correctly when one or both sides are already errored. As a result, calling algorithms do not need to check stream states when responding to an error condition.
5.3.5. `TransformStreamErrorWritableAndUnblockWrite( stream, e )^A
- ! `TransformStreamDefaultControllerClearAlgorithms$A( %stream.[[transformStreamController]]) ◎ Perform ! TransformStreamDefaultControllerClearAlgorithms(stream.[[transformStreamController]]);
- ! `WritableStreamDefaultControllerErrorIfNeeded$A( %stream.[[writable]].[[writableStreamController]], %e ) ◎ Perform ! WritableStreamDefaultControllerErrorIfNeeded(stream.[[writable]].[[writableStreamController]], e).
- ~IF[ %stream.[[backpressure]] ~EQ ~true ] ⇒ ! `TransformStreamSetBackpressure$A( %stream, ~false ) ◎ If stream.[[backpressure]] is true, perform ! TransformStreamSetBackpressure(stream, false).
注記: `TransformStreamDefaultSinkWriteAlgorithm$A 抽象~演算は、 [[backpressureChangePromise]] ~slotに格納された~promiseが解決されるまで,待機することもある。 この, `TransformStreamSetBackpressure$A への~callは、~promiseが常に解決されることを確保する。 ◎ The TransformStreamDefaultSinkWriteAlgorithm abstract operation could be waiting for the promise stored in the [[backpressureChangePromise]] slot to resolve. This call to TransformStreamSetBackpressure ensures that the promise always resolves.
5.3.6. `TransformStreamSetBackpressure( stream, backpressure )^A
- ~Assert: %stream.[[backpressure]] ~NEQ %backpressure ◎ Assert: stream.[[backpressure]] is not backpressure.
- ~IF[ %stream.[[backpressureChangePromise]] ~NEQ ~undefined ] ⇒ ~undefined で %stream.[[backpressureChangePromise]] を`解決する$ ◎ If stream.[[backpressureChangePromise]] is not undefined, resolve stream.[[backpressureChangePromise]] with undefined.
- %stream.[[backpressureChangePromise]] ~SET `新たな~promise$ ◎ Set stream.[[backpressureChangePromise]] to a new promise.
- %stream.[[backpressure]] ~SET %backpressure ◎ Set stream.[[backpressure]] to backpressure.
5.4. ~class `TransformStreamDefaultController^C
`TransformStreamDefaultController$C ~classは、それに結付けられている[ `ReadableStream$C / `WritableStream$C ]の操作を許容する~methodを備える。 `TransformStream$C を構築するとき、`形式変換器$~objには,対応する `TransformStreamDefaultController$C ~instanceが操作するものとして与えられる。 ◎ The TransformStreamDefaultController class has methods that allow manipulation of the associated ReadableStream and WritableStream. When constructing a TransformStream, the transformer object is given a corresponding TransformStreamDefaultController instance to manipulate.
5.4.1. ~class定義
~INFORMATIVE`TransformStreamDefaultController$C ~classは、 `ECMASCRIPT$r 風の構文で書くならば,次のようになる: ◎ If one were to write the TransformStreamDefaultController class in something close to the syntax of [ECMASCRIPT], it would look like
class TransformStreamDefaultController {
`constructor()$tsdc /*
常に投出する
◎
always throws
*/
get `desiredSize()$tsdc
`enqueue(chunk)$tsdc
`error(reason)$tsdc
`terminate()$tsdc
}
5.4.2. 内部~slot
`TransformStreamDefaultController$C の各~instanceは、次の一覧に述べる各種 内部~slotを伴って作成される: ◎ Instances of TransformStreamDefaultController are created with the internal slots described in the following table:
内部~slot | 説明0(参考) |
---|---|
[[controlledTransformStream]] | 制御先の `TransformStream$C ~instance。 `IsTransformStreamDefaultController$A による~brand検査-時にも利用される。 ◎ The TransformStream instance controlled; also used for the IsTransformStreamDefaultController brand check |
[[flushAlgorithm]] | ~promiseを返す~algo — それは、要請された~closeを`形式変換器$に通信する。 ◎ A promise-returning algorithm which communicates a requested close to the transformer |
[[transformAlgorithm]] | 1 個の引数(形式変換への`~chunk$)をとり,~promiseを返す~algo — それは、`形式変換器$に形式変換nを遂行するよう要請する。 ◎ A promise-returning algorithm, taking one argument (the chunk to transform), which requests the transformer perform its transformation |
5.4.3. `new TransformStreamDefaultController()^tsdc
`TransformStreamDefaultController()^tsdc 構築子は、直には利用できない。 — `TransformStreamDefaultController$C ~instanceは、 `TransformStream$C を構築する間に自動的に作成される。 ◎ The TransformStreamDefaultController constructor cannot be used directly; TransformStreamDefaultController instances are created automatically during TransformStream construction.
- ~THROW `TypeError^b ◎ Throw a TypeError exception.
5.4.4. `TransformStreamDefaultController$C ~prototypeの~prop
5.4.4.1. `get desiredSize^tsdc
`desiredSize^c 取得子は、`~streamの内部~queueの残り~size$を返す。 それは、~queueが溢れた場合には,負になり得る。 ◎ The desiredSize getter returns the desired size to fill the readable side’s internal queue. It can be negative, if the queue is over-full.
- ~IF[ ! `IsTransformStreamDefaultController$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsTransformStreamDefaultController(this) is false, throw a TypeError exception.
- %readableController ~LET ~this.[[controlledTransformStream]].[[readable]].[[readableStreamController]] ◎ Let readableController be this.[[controlledTransformStream]].[[readable]].[[readableStreamController]].
- ~RET ! `ReadableStreamDefaultControllerGetDesiredSize$A( %readableController ) ◎ Return ! ReadableStreamDefaultControllerGetDesiredSize(readableController).
5.4.4.2. `enqueue( chunk )^tsdc
`enqueue^tsdc ~methodは、所与の`~chunk$を `可読~側$に~enqueueする。 ◎ The enqueue method will enqueue a given chunk in the readable side.
- ~IF[ ! `IsTransformStreamDefaultController$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsTransformStreamDefaultController(this) is false, throw a TypeError exception.
- ? `TransformStreamDefaultControllerEnqueue$A( ~this, %chunk ) ◎ Perform ? TransformStreamDefaultControllerEnqueue(this, chunk).
5.4.4.3. `error( reason )^tsdc
`error^c ~methodは、制御先の`形式変換~stream$の `可読~側$, `可書~側$ とも~errorにする — 以降の相互作用は、すべて所与の %reason で失敗し, 形式変換n用に~queueされたどの`~chunk$も破棄されることになる。 ◎ The error method will error both the readable side and the writable side of the controlled transform stream, making all future interactions fail with the given reason. Any chunks queued for transformation will be discarded.
- ~IF[ ! `IsTransformStreamDefaultController$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsTransformStreamDefaultController(this) is false, throw a TypeError exception.
- ! `TransformStreamDefaultControllerError$A( ~this, %reason ) ◎ Perform ! TransformStreamDefaultControllerError(this, reason).
5.4.4.4. `terminate()^tsdc
`terminate^tsdc ~methodは、制御先の`形式変換~stream$の `可読~側$を~closeして, `可書~側$を~errorにする。 これは、`形式変換器$が[ `可書~側$に書込された`~chunk$たちの一部分だけ消費する必要がある ]ときに有用になる。 ◎ The terminate method will close the readable side and error the writable side of the controlled transform stream. This is useful when the transformer only needs to consume a portion of the chunks written to the writable side.
- ~IF[ ! `IsTransformStreamDefaultController$A( ~this ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsTransformStreamDefaultController(this) is false, throw a TypeError exception.
- ! `TransformStreamDefaultControllerTerminate$A( ~this ) ◎ Perform ! TransformStreamDefaultControllerTerminate(this).
5.5. 形式変換~streamの既定の制御器~用の抽象~演算
5.5.1. `IsTransformStreamDefaultController( x )^A
- ~IF[ `Type$A( %x ) ~NEQ `Object^b ] ⇒ ~RET ~false ◎ If Type(x) is not Object, return false.
- ~IF[ %x は [[controlledTransformStream]] 内部~slotを持たない ] ⇒ ~RET ~false ◎ If x does not have an [[controlledTransformStream]] internal slot, return false.
- ~RET ~true ◎ Return true.
5.5.2. `SetUpTransformStreamDefaultController( stream, controller, transformAlgorithm, flushAlgorithm )^A
- ~Assert: ! `IsTransformStream$A( %stream ) ~EQ ~true ◎ Assert: ! IsTransformStream(stream) is true.
- ~Assert: %stream.[[transformStreamController]] ~EQ ~undefined ◎ Assert: stream.[[transformStreamController]] is undefined.
- %controller.[[controlledTransformStream]] ~SET %stream ◎ Set controller.[[controlledTransformStream]] to stream.
- %stream.[[transformStreamController]] ~SET %controller ◎ Set stream.[[transformStreamController]] to controller.
- %controller.[[transformAlgorithm]] ~SET %transformAlgorithm ◎ Set controller.[[transformAlgorithm]] to transformAlgorithm.
- %controller.[[flushAlgorithm]] ~SET %flushAlgorithm ◎ Set controller.[[flushAlgorithm]] to flushAlgorithm.
5.5.3. `SetUpTransformStreamDefaultControllerFromTransformer( stream, transformer )^A
- ~Assert: %transformer ~NEQ ~undefined ◎ Assert: transformer is not undefined.
- %controller ~LET `ObjectCreate$A( `TransformStreamDefaultController$C の `prototype^c ~propの元の値 ) ◎ Let controller be ObjectCreate(the original value of TransformStreamDefaultController's prototype property).
-
%transformAlgorithm ~LET 引数 ( %chunk ) をとり,次を走らす手続き: ◎ Let transformAlgorithm be the following steps, taking a chunk argument:
- %result ~LET `TransformStreamDefaultControllerEnqueue$A( %controller, %chunk ) ◎ Let result be TransformStreamDefaultControllerEnqueue(controller, chunk).
- ~IF[ %result は`中途完了$である ] ⇒ ~RET %result.[[Value]] で`却下される~promise$ ◎ If result is an abrupt completion, return a promise rejected with result.[[Value]].
- ~RET ~undefined で`解決される~promise$ ◎ Otherwise, return a promise resolved with undefined.
- %transformMethod ~LET ? `GetV$A( %transformer, `transform^l ) ◎ Let transformMethod be ? GetV(transformer, "transform").
-
If transformMethod is not undefined,
- ~IF[ ! `IsCallable$A( %transformMethod ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsCallable(transformMethod) is false, throw a TypeError exception.
-
%transformAlgorithm ~SET 引数 ( %chunk ) をとり,次を走らす手続き: ◎ Set transformAlgorithm to the following steps, taking a chunk argument:
- %transformPromise ~LET ! `PromiseCall$A( %transformMethod, %transformer, « %chunk, %controller » ) ◎ Let transformPromise be ! PromiseCall(transformMethod, transformer, « chunk, controller »).
-
~RET [ 引数 ( %e ) で~callされたとき,次の手続きを遂行する却下~handler ]で %transformPromise を`変形-$した結果: ◎ Return the result of transforming transformPromise with a rejection handler that, when called with argument e, performs the following steps:
- ! `TransformStreamError$A( %stream, %e ) ◎ Perform ! TransformStreamError(stream, e).
- ~THROW %e ◎ Throw e.
- %flushAlgorithm ~LET ? `CreateAlgorithmFromUnderlyingMethod$A( %transformer, `flush^l, `0^b, « %controller » ) ◎ Let flushAlgorithm be ? CreateAlgorithmFromUnderlyingMethod(transformer, "flush", 0, « controller »).
- ! `SetUpTransformStreamDefaultController$A( %stream, %controller, %transformAlgorithm, %flushAlgorithm ) ◎ Perform ! SetUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm).
5.5.4. `TransformStreamDefaultControllerClearAlgorithms( controller )^A
この抽象~演算は,~streamが~closeされるか~errorしたときに~callされ、各種~algoへの参照を除去することにより,それ以降は それらが実行されないようにする。 その結果、`形式変換器$( `TransformStream$C ~obj)自身が — まだ参照されていても — ~garbage収集されることを許可する。 ◎ This abstract operation is called once the stream is closed or errored and the algorithms will not be executed any more. By removing the algorithm references it permits the transformer object to be garbage collected even if the TransformStream itself is still referenced.
この~algoの結果は,現在は観測-可能でないが、~JSに 弱い参照が追加されたなら,そうなり得る。 追加されなくとも、実装は,類似する手続きを含めたいと求めるであろう。 ◎ The results of this algorithm are not currently observable, but could become so if JavaScript eventually adds weak references. But even without that factor, implementations will likely want to include similar steps.
- %controller.[[transformAlgorithm]] ~SET ~undefined ◎ Set controller.[[transformAlgorithm]] to undefined.
- %controller.[[flushAlgorithm]] ~SET ~undefined ◎ Set controller.[[flushAlgorithm]] to undefined.
5.5.5. `TransformStreamDefaultControllerEnqueue( controller, chunk )^A
他の仕様は、`~chunk$たちを`可読~側$に~enqueueしたいと望むなら,この抽象~演算を~callできる — 開発者が[ ~streamに結付けられた制御器~objを利用して~chunkたちを~enqueueする ]のと同じ仕方で。 仕様は、自身が作成しなかった~streamに対し,これを行うべきでない ◎ This abstract operation can be called by other specifications that wish to enqueue chunks in the readable side, in the same way a developer would enqueue chunks using the stream’s associated controller object. Specifications should not do this to streams they did not create.
- %stream ~LET %controller.[[controlledTransformStream]] ◎ Let stream be controller.[[controlledTransformStream]].
- %readableController ~LET %stream.[[readable]].[[readableStreamController]] ◎ Let readableController be stream.[[readable]].[[readableStreamController]].
- ~IF[ ! `ReadableStreamDefaultControllerCanCloseOrEnqueue$A( %readableController ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController) is false, throw a TypeError exception.
- %enqueueResult ~LET `ReadableStreamDefaultControllerEnqueue$A( %readableController, %chunk ) ◎ Let enqueueResult be ReadableStreamDefaultControllerEnqueue(readableController, chunk).
-
~IF[ %enqueueResult は`中途完了$である ]: ◎ If enqueueResult is an abrupt completion,
- ! `TransformStreamErrorWritableAndUnblockWrite$A( %stream, %enqueueResult.[[Value]] ) ◎ Perform ! TransformStreamErrorWritableAndUnblockWrite(stream, enqueueResult.[[Value]]).
- ~THROW %stream.[[readable]].[[storedError]] ◎ Throw stream.[[readable]].[[storedError]].
- %backpressure ~LET ! `ReadableStreamDefaultControllerHasBackpressure$A( %readableController ) ◎ Let backpressure be ! ReadableStreamDefaultControllerHasBackpressure(readableController).
-
~IF[ %backpressure ~NEQ %stream.[[backpressure]] ]: ◎ If backpressure is not stream.[[backpressure]],
- ~Assert: %backpressure ~EQ ~true ◎ Assert: backpressure is true.
- ! `TransformStreamSetBackpressure$A( %stream, ~true ) ◎ Perform ! TransformStreamSetBackpressure(stream, true).
5.5.6. `TransformStreamDefaultControllerError( controller, e )^A
他の仕様は、形式変換~streamを~errorした状態に移行させたいと望むなら,この抽象~演算を~callできる — 開発者が[ ~streamに結付けられた制御器~objを利用して,~errorにする ]のと同じ仕方で。 仕様は、自身が作成しなかった~streamに対し,これを行うべきでない。 ◎ This abstract operation can be called by other specifications that wish to move a transform stream to an errored state, in the same way a developer would error a stream using its associated controller object. Specifications should not do this to streams they did not create.
- ! `TransformStreamError$A( %controller.[[controlledTransformStream]], %e ) ◎ Perform ! TransformStreamError(controller.[[controlledTransformStream]], e).
5.5.7. `TransformStreamDefaultControllerTerminate( controller )^A
他の仕様は、形式変換~streamを終了したいと望むなら,この抽象~演算を~callできる — 開発者が作成した~streamが[ それに結付けられた制御器~objにより~closeされる ]のと同じ仕方で。 仕様は、自身が作成しなかった~streamに対し,これを行うべきでない。 ◎ This abstract operation can be called by other specifications that wish to terminate a transform stream, in the same way a developer-created stream would be closed by its associated controller object. Specifications should not do this to streams they did not create.
- %stream ~LET %controller.[[controlledTransformStream]] ◎ Let stream be controller.[[controlledTransformStream]].
- %readableController ~LET %stream.[[readable]].[[readableStreamController]] ◎ Let readableController be stream.[[readable]].[[readableStreamController]].
- ~IF[ ! `ReadableStreamDefaultControllerCanCloseOrEnqueue$A( %readableController ) ~EQ ~true ] ⇒ ! `ReadableStreamDefaultControllerClose$A( %readableController ) ◎ If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController) is true, perform ! ReadableStreamDefaultControllerClose(readableController).
- %error ~LET ~streamは終了されたことを指示する, `TypeError^b 例外 ◎ Let error be a TypeError exception indicating that the stream has been terminated.
- ! `TransformStreamErrorWritableAndUnblockWrite$A( %stream, %error ) ◎ Perform ! TransformStreamErrorWritableAndUnblockWrite(stream, error).
5.6. 形式変換~streamの既定の槽~用の抽象~演算
5.6.1. `TransformStreamDefaultSinkWriteAlgorithm( stream, chunk )^A
- ~Assert: %stream.[[writable]].[[state]] ~EQ `writable^l ◎ Assert: stream.[[writable]].[[state]] is "writable".
- %controller ~LET %stream.[[transformStreamController]] ◎ Let controller be stream.[[transformStreamController]].
-
~IF[ %stream.[[backpressure]] ~EQ ~true ]: ◎ If stream.[[backpressure]] is true,
- %backpressureChangePromise ~LET %stream.[[backpressureChangePromise]] ◎ Let backpressureChangePromise be stream.[[backpressureChangePromise]].
- ~Assert: %backpressureChangePromise ~NEQ ~undefined ◎ Assert: backpressureChangePromise is not undefined.
-
~RET [ 次の手続きを遂行する充足~handler ]で %backpressureChangePromise を`変形-$した結果: ◎ Return the result of transforming backpressureChangePromise with a fulfillment handler which performs the following steps:
- %writable ~LET %stream.[[writable]] ◎ Let writable be stream.[[writable]].
- %state ~LET %writable.[[state]] ◎ Let state be writable.[[state]].
- ~IF[ %state ~EQ `erroring^l ] ⇒ ~THROW %writable.[[storedError]] ◎ If state is "erroring", throw writable.[[storedError]].
- ~Assert: %state ~EQ `writable^l ◎ Assert: state is "writable".
- ~RET 次を遂行した結果 ⇒ %controller.[[transformAlgorithm]]( %chunk ) ◎ Return the result of performing controller.[[transformAlgorithm]], passing chunk.
- ~RET 次を遂行した結果 ⇒ %controller.[[transformAlgorithm]]( %chunk ) ◎ Return the result of performing controller.[[transformAlgorithm]], passing chunk.
5.6.2. `TransformStreamDefaultSinkAbortAlgorithm( stream, reason )^A
- ! `TransformStreamError$A( %stream, %reason ) ◎ Perform ! TransformStreamError(stream, reason).
- ~RET ~undefined で`解決される~promise$ ◎ Return a promise resolved with undefined.
5.6.3. `TransformStreamDefaultSinkCloseAlgorithm( stream )^A
- %readable ~LET %stream.[[readable]] ◎ Let readable be stream.[[readable]].
- %controller ~LET %stream.[[transformStreamController]] ◎ Let controller be stream.[[transformStreamController]].
- %flushPromise ~LET 次を遂行した結果 ⇒ %controller.[[flushAlgorithm]]() ◎ Let flushPromise be the result of performing controller.[[flushAlgorithm]].
- ! `TransformStreamDefaultControllerClearAlgorithms$A( %controller ) ◎ Perform ! TransformStreamDefaultControllerClearAlgorithms(controller).
-
~RET 次に与える[ 充足~handler, 却下~handler ]で %flushPromise を`変形-$した結果: ◎ Return the result of transforming flushPromise with:
-
充足~handlerは、次の手続きを遂行する: ◎ A fulfillment handler that performs the following steps:
- ~IF[ %readable.[[state]] ~EQ `errored^l ] ⇒ ~THROW %readable.[[storedError]] ◎ If readable.[[state]] is "errored", throw readable.[[storedError]].
- %readableController ~LET %readable.[[readableStreamController]] ◎ Let readableController be readable.[[readableStreamController]].
- ~IF[ ! `ReadableStreamDefaultControllerCanCloseOrEnqueue$A( %readableController ) ~EQ ~true ] ⇒ ! `ReadableStreamDefaultControllerClose$A( %readableController ) ◎ If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController) is true, perform ! ReadableStreamDefaultControllerClose(readableController).
-
却下~handlerは、引数 ( %r ) で~callされたとき,次の手続きを遂行する: ◎ A rejection handler that, when called with argument r, performs the following steps:
- ! `TransformStreamError$A( %stream, %r ) ◎ Perform ! TransformStreamError(stream, r).
- ~THROW %readable.[[storedError]] ◎ Throw readable.[[storedError]].
-
5.7. 形式変換~streamの既定の源~用の抽象~演算
5.7.1. `TransformStreamDefaultSourcePullAlgorithm( stream )^A
- ~Assert: %stream.[[backpressure]] ~EQ ~true ◎ Assert: stream.[[backpressure]] is true.
- ~Assert: %stream.[[backpressureChangePromise]] ~NEQ ~undefined ◎ Assert: stream.[[backpressureChangePromise]] is not undefined.
- ! `TransformStreamSetBackpressure$A( %stream, ~false ) ◎ Perform ! TransformStreamSetBackpressure(stream, false).
- ~RET %stream.[[backpressureChangePromise]] ◎ Return stream.[[backpressureChangePromise]].
6. 他の~stream~APIと演算
6.1. ~queuing策
6.1.1. ~queuing策~API
~INFORMATIVE[ `ReadableStream()$rs / `WritableStream()$ws / `TransformStream()$ts ]構築子は、[ 作成されている~stream用に適切な`~queuing策$ ]を表現している引数を受容する。 そのような~objは、次に挙げる~propを包含する: ◎ The ReadableStream(), WritableStream(), and TransformStream() constructors all accept at least one argument representing an appropriate queuing strategy for the stream being created. Such objects contain the following properties:
- `size(chunk)@qs (非~byte~stream用に限る) ◎ size(chunk) (non-byte streams only)
- この関数は、所与の`~chunk$値の~sizeを算出した結果を返す。 ◎ A function that computes and returns the size of the given chunk value.
- 結果は、`背圧$を決定するために利用される。 それは、適切な `desiredSize^c ~prop — ~queuing策がどこで利用されているかに依存して,[ %defaultController.`desiredSize$rsdc, %byteController.`desiredSize$rbsc, %writer.`desiredSize$dw ]のいずれか — を介して~~露わになる。 可読~stream用には、それは,`下層~源$の `pull()$src ~methodがいつ~callされるかも統治する。 ◎ The result is used to determine backpressure, manifesting via the appropriate desiredSize property: either defaultController.desiredSize, byteController.desiredSize, or writer.desiredSize, depending on where the queuing strategy is being used. For readable streams, it also governs when the underlying source’s pull() method is called.
- この関数は、冪等かつ, 副作用は生じないようにする必要がある。 さもなければ、ごく変則的な結果が生じ得る。 ◎ This function has to be idempotent and not cause side effects; very strange results can occur otherwise.
- この関数は、`可読~byte~stream$には利用されない — ~chunkたちは、常に~byte数で測られるので。 ◎ For readable byte streams, this function is not used, as chunks are always measured in bytes.
- `highWaterMark@qs
- 負でない~number。 この~queuing策を利用している~streamの`限界水位$を指示する。 ◎ A non-negative number indicating the high water mark of the stream using this queuing strategy.
~queuing策~objが期待される所では、これらの~propを伴うどの~objも利用できる。 しかしながら,ある種の事例~用に共通的な語彙を供するためとして、組込みの~queuing策~class — `ByteLengthQueuingStrategy$C, `CountQueuingStrategy$C — も供される。 ◎ Any object with these properties can be used when a queuing strategy object is expected. However, we provide two built-in queuing strategy classes that provide a common vocabulary for certain cases: ByteLengthQueuingStrategy and CountQueuingStrategy.
6.1.2 `ByteLengthQueuingStrategy^C ~class
~byte列を扱うときに共通的な`~queuing策$は、流入`~chunk$たちの `byteLength^m ~propの累積が,指定された`限界水位$に達するまで、待機することである。 そのようなわけで,これは、~streamを構築するときに利用できるような,組込みの`~queuing策$として供される。 ◎ A common queuing strategy when dealing with bytes is to wait until the accumulated byteLength properties of the incoming chunks reaches a specified high-water mark. As such, this is provided as a built-in queuing strategy that can be used when constructing streams.
`可読~stream$/`可書~stream$を作成する際には、~byte数による~queuing策を直に給せる: ◎ When creating a readable stream or writable stream, you can supply a byte-length queuing strategy directly:
const %stream = new ReadableStream( { ... }, new ByteLengthQueuingStrategy({ %highWaterMark: 16 * 1024 }) );
この事例では、可読~stream実装が 下層~源へ`背圧$合図の送信を開始するまでに、可読~streamの`下層~源$に~~総計 16 KiB 程の`~chunk$たちを~enqueueできる。 ◎ In this case, 16 KiB worth of chunks can be enqueued by the readable stream’s underlying source before the readable stream implementation starts sending backpressure signals to the underlying source.
const %stream = new WritableStream( { ... }, new ByteLengthQueuingStrategy({ %highWaterMark: 32 * 1024 }) );
この事例では、`下層~槽$への以前の書込が完遂するまで待機する間,可書~streamが `生産器$へ向けて`背圧$合図の送信を開始するまでに、~~総計 32 KiB 程の`~chunk$たちを可書~streamの内部~queue内に累積し得る。 ◎ In this case, 32 KiB worth of chunks can be accumulated in the writable stream’s internal queue, waiting for previous writes to the underlying sink to finish, before the writable stream starts sending backpressure signals to any producers.
注記: `可読~byte~stream$には、 `ByteLengthQueuingStrategy$C の利用は必要とされない — その~chunk数は常に~byte数で測られるので。 `ByteLengthQueuingStrategy$C で~byte~streamを構築しようと試みても,失敗することになる。 ◎ It is not necessary to use ByteLengthQueuingStrategy with readable byte streams, as they always measure chunks in bytes. Attempting to construct a byte stream with a ByteLengthQueuingStrategy will fail.
6.1.2.1. ~class定義
~INFORMATIVE`ByteLengthQueuingStrategy$C ~classは、 `ECMASCRIPT$r 風の構文で書くならば、次のようになる: ◎ If one were to write the ByteLengthQueuingStrategy class in something close to the syntax of [ECMASCRIPT], it would look like
class ByteLengthQueuingStrategy { `constructor({ highWaterMark })$blqs `size(chunk)$blqs }
`ByteLengthQueuingStrategy^C の各~instanceは、追加で,自前の~data~prop `highWaterMark^m がその構築子により設定される。 ◎ Each ByteLengthQueuingStrategy instance will additionally have an own data property highWaterMark set by its constructor.
6.1.2.2. `new ByteLengthQueuingStrategy({ highWaterMark })^m
この構築子は、`限界水位$を与える負でない~numberをとり,それを~objの~propとして格納する。 ◎ The constructor takes a non-negative number for the high-water mark, and stores it on the object as a property.
- ! `CreateDataProperty$A( ~this, `highWaterMark^l, %highWaterMark ) ◎ Perform ! CreateDataProperty(this, "highWaterMark", highWaterMark).
6.1.2.3. `ByteLengthQueuingStrategy^C ~prototypeの各種~prop
6.1.2.3.1. `size(chunk)^m
`size()^m ~methodは、所与の`~chunk$の `byteLength^m ~propを返す(~chunkがそれを持たない場合、 ~undefined を返し,この策を利用している~streamを~errorにすることになる) ◎ The size method returns the given chunk’s byteLength property. (If the chunk doesn’t have one, it will return undefined, causing the stream using this strategy to error.)
この~methodは、その ~this 値が `ByteLengthQueuingStrategy^C ~objであることを要求しない点で,意図的に汎化してある。 ◎ This method is intentionally generic; it does not require that its this value be a ByteLengthQueuingStrategy object.
- ~RET ? `GetV$A( %chunk, `byteLength^l ) ◎ Return ? GetV(chunk, "byteLength").
6.1.3. `CountQueuingStrategy^C ~class
汎用~objの~streamを扱うときに共通的な`~queuing策$は、単純に,[ 累積した`~chunk$の個数を,指定された`限界水位$に達するまで数え続ける ]ものである。 そのようなわけで、この策も ~out-of-the-boxで供される。 ◎ A common queuing strategy when dealing with streams of generic objects is to simply count the number of chunks that have been accumulated so far, waiting until this number reaches a specified high-water mark. As such, this strategy is also provided out of the box.
`可読~stream$/`可書~stream$を作成するときは、~chunk数による~queuing策を直に給せる: ◎ When creating a readable stream or writable stream, you can supply a count queuing strategy directly:
const %stream = new ReadableStream( { ... }, new CountQueuingStrategy({ %highWaterMark: 10 }) );
この事例では、可読~stream実装が `下層~源$へ向けて`背圧$合図の送信を開始するまでに、(種類は問わず) 10 個の`~chunk$を,可読~streamの`下層~源$に~enqueueし得る。 ◎ In this case, 10 chunks (of any kind) can be enqueued by the readable stream’s underlying source before the readable stream implementation starts sending backpressure signals to the underlying source.
const %stream = new WritableStream( { ... }, new CountQueuingStrategy({ %highWaterMark: 5 }) );
この事例では、`下層~槽$への以前の書込が完遂するまで待機している間,可書~streamが `生産器$へ向けて`背圧$合図の送信を開始するまでに、可書~streamの内部~queue内に(種類は問わず) 5 個の`~chunk$を累積し得る。 ◎ In this case, five chunks (of any kind) can be accumulated in the writable stream’s internal queue, waiting for previous writes to the underlying sink to finish, before the writable stream starts sending backpressure signals to any producers.
6.1.3.1. ~class定義
~INFORMATIVE`CountQueuingStrategy$C ~classは、 `ECMASCRIPT$r 風の構文で書くならば,次のようになる: ◎ If one were to write the CountQueuingStrategy class in something close to the syntax of [ECMASCRIPT], it would look like
class CountQueuingStrategy { `constructor({ highWaterMark })$cqs `size()$cqs }
`CountQueuingStrategy^C の各~instanceは、追加で,自前の~data~prop `highWaterMark^m が,その構築子により設定される。 ◎ Each CountQueuingStrategy instance will additionally have an own data property highWaterMark set by its constructor.
6.1.3.2. `new CountQueuingStrategy({ highWaterMark })^m
この構築子は、`限界水位$を与える負でない~numberをとり,それを~objの~propとして格納する。 ◎ The constructor takes a non-negative number for the high-water mark, and stores it on the object as a property.
- ! `CreateDataProperty$A( ~this, `highWaterMark^l, %highWaterMark ) ◎ Perform ! CreateDataProperty(this, "highWaterMark", highWaterMark).
6.1.3.3. `CountQueuingStrategy^C ~prototypeの各種~prop
6.1.3.3.1. `size()^m
`size()^m ~methodは、常に 1 を返す — 合計~queue~sizeが,~queue内にある`~chunk$の個数になるように。 ◎ The size method returns one always, so that the total queue size is a count of the number of chunks in the queue.
この~methodは、その ~this 値が `CountQueuingStrategy^C ~objであることを要求しない点で,意図的に汎化してある。 ◎ This method is intentionally generic; it does not require that its this value be a CountQueuingStrategy object.
- ~RET `1^b ◎ Return 1.
6.2. 個別~size付き~queue演算
この仕様における各種~streamは、 “個別~size付き~queue” ( `queue-with-sizes^en )と称される~data構造を利用して,~queue-upされた値を, それに決定された~sizeと伴に格納する。 個別~size付き~queueは、種々の仕様~levelの~objに包含され,[ 常に, [[queue]], [[queueTotalSize]] と命名され,~pairにされる 2 つの内部~slot ]を持つ~objにより表現される。 [[queue]] は,それぞれが[ [[value]], [[size]] ]~fieldを伴う一連の~Recordからなる`~List$であり、 [[queueTotalSize]] は,~JS `Number$b — すなわち,倍精度~浮動小数点~number — をとる。 ◎ The streams in this specification use a "queue-with-sizes" data structure to store queued up values, along with their determined sizes. Various specification objects contain a queue-with-sizes, represented by the object having two paired internal slots, always named [[queue]] and [[queueTotalSize]]. [[queue]] is a List of Records with [[value]] and [[size]] fields, and [[queueTotalSize]] is a JavaScript Number, i.e. a double-precision floating point number.
個別~size付き~queueを包含する~obj上で演算するときには、 この 2 つの内部~slotが同期し続けることを確保するため,以下の抽象~演算が利用される。 ◎ The following abstract operations are used when operating on objects that contain queues-with-sizes, in order to ensure that the two internal slots stay synchronized.
ここに指定される~frameworkは,合計が [[queueTotalSize]] ~slotに~~収まり続けるようにするが、浮動小数点 算術の精度には限りがあるため, [[queue]] 内の すべての`~chunk$の~sizeを加算していくことに等価ではない。 (しかしながら,この相違が生じるのは、~chunkたちの~sizeの変動幅が莫大になるとき( 〜 1015 )か, 数 100 京 個の~chunkが~enqueueされたときに限られる。) ◎ Due to the limited precision of floating-point arithmetic, the framework specified here, of keeping a running total in the [[queueTotalSize]] slot, is not equivalent to adding up the size of all chunks in [[queue]]. (However, this only makes a difference when there is a huge (~1015) variance in size between chunks, or when trillions of chunks are enqueued.)
6.2.1. `DequeueValue( container )^A
- ~Assert: %container は [[queue]], [[queueTotalSize]] 両~内部~slotを持つ ◎ Assert: container has [[queue]] and [[queueTotalSize]] internal slots.
- ~Assert: %container.[[queue]] は空でない ◎ Assert: container.[[queue]] is not empty.
- %pair ~LET %container.[[queue]] の最初の要素 ◎ Let pair be the first element of container.[[queue]].
- %container.[[queue]] から %pair を除去する — 後続の要素たちは~~先頭へ一つずらす ◎ Remove pair from container.[[queue]], shifting all other elements downward (so that the second becomes the first, and so on).
- %container.[[queueTotalSize]] ~SET %container.[[queueTotalSize]] − %pair.[[size]] ◎ Set container.[[queueTotalSize]] to container.[[queueTotalSize]] − pair.[[size]].
- ~IF[ %container.[[queueTotalSize]] ~LT `0^b (これは丸め誤差に因り生じ得る) ] ⇒ %container.[[queueTotalSize]] ~SET `0^b ◎ If container.[[queueTotalSize]] < 0, set container.[[queueTotalSize]] to 0. (This can occur due to rounding errors.)
- ~RET %pair.[[value]] ◎ Return pair.[[value]].
6.2.2. `EnqueueValueWithSize( container, value, size )^A
- ~Assert: %container は [[queue]], [[queueTotalSize]] 両~内部~slotを持つ ◎ Assert: container has [[queue]] and [[queueTotalSize]] internal slots.
- %size ~LET ? `ToNumber$A( %size ) ◎ Let size be ? ToNumber(size).
- ~IF[ ! `IsFiniteNonNegativeNumber$A( %size ) ~EQ ~false ] ⇒ ~THROW `RangeError^b ◎ If ! IsFiniteNonNegativeNumber(size) is false, throw a RangeError exception.
- %container.[[queue]] の~~末尾に `~Record${ [[value]]: %value, [[size]]: %size } を付加する ◎ Append Record {[[value]]: value, [[size]]: size} as the last element of container.[[queue]].
- %container.[[queueTotalSize]] ~SET %container.[[queueTotalSize]] + %size ◎ Set container.[[queueTotalSize]] to container.[[queueTotalSize]] + size.
6.2.3. `PeekQueueValue( container )^A
- ~Assert: %container は [[queue]], [[queueTotalSize]] 両~内部~slotを持つ ◎ Assert: container has [[queue]] and [[queueTotalSize]] internal slots.
- ~Assert: %container.[[queue]] は空でない ◎ Assert: container.[[queue]] is not empty.
- %pair ~LET %container.[[queue]] の最初の要素 ◎ Let pair be the first element of container.[[queue]].
- ~RET %pair.[[value]] ◎ Return pair.[[value]].
6.2.4. `ResetQueue( container )^A
- ~Assert: %container は [[queue]], [[queueTotalSize]] 両~内部~slotを持つ ◎ Assert: container has [[queue]] and [[queueTotalSize]] internal slots.
- %container.[[queue]] ~SET 新たな空`~List$ ◎ Set container.[[queue]] to a new empty List.
- %container.[[queueTotalSize]] ~SET `0^b ◎ Set container.[[queueTotalSize]] to 0.
6.3. その他の演算
この仕様にて多目的に利用される抽象~演算を,以下に定義する: ◎ A few abstract operations are used in this specification for utility purposes. We define them here.
6.3.1. `CreateAlgorithmFromUnderlyingMethod ( underlyingObject , methodName , algoArgCount , extraArgs )^A
- ~Assert: %underlyingObject ~NEQ ~undefined ◎ Assert: underlyingObject is not undefined.
- ~Assert: ! `IsPropertyKey$A( %methodName ) ~EQ ~true ◎ Assert: ! IsPropertyKey(methodName) is true.
- ~Assert: %algoArgCount ~IN { `0^b, `1^b } ◎ Assert: algoArgCount is 0 or 1.
- ~Assert: %extraArgs は`~List$である ◎ Assert: extraArgs is a List.
- %method ~LET ? `GetV$A( %underlyingObject, %methodName ) ◎ Let method be ? GetV(underlyingObject, methodName).
-
~IF[ %method ~NEQ ~undefined ]: ◎ If method is not undefined,
- ~IF[ ! `IsCallable$A( %method ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsCallable(method) is false, throw a TypeError exception.
-
~IF[ %algoArgCount ~EQ `0^b ] ⇒ ~RET 次の手続きを遂行する~algo: ◎ If algoArgCount is 0, return an algorithm that performs the following steps:
- ~RET ! `PromiseCall$A( %method, %underlyingObject, %extraArgs ) ◎ Return ! PromiseCall(method, underlyingObject, extraArgs).
-
~RET 引数 ( %arg ) をとり,次の手続きを遂行する~algo: ◎ Otherwise, return an algorithm that performs the following steps, taking an arg argument:
- %fullArgs ~LET 順に,次のものからなる`~List$ ⇒# %arg, %extraArgs の要素たち ◎ Let fullArgs be a List consisting of arg followed by the elements of extraArgs in order.
- ~RET ! `PromiseCall$A( %method, %underlyingObject, %fullArgs ) ◎ Return ! PromiseCall(method, underlyingObject, fullArgs).
- ~RET [ ~undefined で`解決される~promise$ ]を返す~algo ◎ Return an algorithm which returns a promise resolved with undefined.
6.3.2. `InvokeOrNoop( O, P, args )^A
`InvokeOrNoop$A は、~methodが不在のときは ~undefined を返すように, `ECMASCRIPT$r の抽象~演算 `Invoke$A を少しばかり改変したものである。 ◎ InvokeOrNoop is a slight modification of the [ECMASCRIPT] Invoke abstract operation to return undefined when the method is not present.
- ~Assert: %O ~NEQ ~undefined ◎ Assert: O is not undefined.
- ~Assert: `IsPropertyKey$A(%P) ~EQ ~true ◎ Assert: ! IsPropertyKey(P) is true.
- ~Assert: %args は`~List$である ◎ Assert: args is a List.
- %method ~LET ? `GetV$A( %O, %P ) ◎ Let method be ? GetV(O, P).
- ~IF[ %method ~EQ ~undefined ] ⇒ ~RET ~undefined ◎ If method is undefined, return undefined.
- ~RET ? `Call$A( %method, %O, %args ) ◎ Return ? Call(method, O, args).
6.3.3. `IsFiniteNonNegativeNumber( v )^A
- ~IF[ `IsNonNegativeNumber$A( %v ) ~EQ ~false ] ⇒ ~RET ~false ◎ If ! IsNonNegativeNumber(v) is false, return false.
- ~IF[ %v ~EQ `+∞^b ] ⇒ ~RET ~false ◎ If v is +∞, return false.
- ~RET ~true ◎ Return true.
6.3.4. `IsNonNegativeNumber( v )^A
- ~IF[ `Type$A( %v ) ~NEQ `Number$b ] ⇒ ~RET ~false ◎ If Type(v) is not Number, return false.
- ~IF[ %v ~EQ `NaN^b ] ⇒ ~RET ~false ◎ If v is NaN, return false.
- ~IF[ %v ~LT `0^b ] ⇒ ~RET ~false ◎ If v < 0, return false.
- ~RET ~true ◎ Return true.
6.3.5. `PromiseCall( F, V, args )^A
`PromiseCall^A は、~methodに対し働く,`~promise-calling$の変種である。 ◎ PromiseCall is a variant of promise-calling that works on methods.
- ~Assert: ! `IsCallable$A( %F ) ~EQ ~true ◎ Assert: ! IsCallable(F) is true.
- ~Assert: %V ~NEQ ~undefined ◎ Assert: V is not undefined.
- ~Assert: %args は`~List$である ◎ Assert: args is a List.
- %returnValue ~LET `Call$A( %F, %V, %args ) ◎ Let returnValue be Call(F, V, args).
- ~IF[ %returnValue は`中途完了$である ] ⇒ ~RET %returnValue.[[Value]] で`却下される~promise$ ◎ If returnValue is an abrupt completion, return a promise rejected with returnValue.[[Value]].
- ~RET %returnValue.[[Value]] で`解決される~promise$ ◎ Otherwise, return a promise resolved with returnValue.[[Value]].
6.3.6. `TransferArrayBuffer( O )^A
- ~Assert:`Type$A( %O ) ~EQ `Object^b ◎ Assert: Type(O) is Object.
- ~Assert: %O は [[ArrayBufferData]] 内部~slotを持つ ◎ Assert: O has an [[ArrayBufferData]] internal slot.
- ~Assert: ! `IsDetachedBuffer$A( %O ) ~EQ ~false ◎ Assert: ! IsDetachedBuffer(O) is false.
- %arrayBufferData ~LET %O.[[ArrayBufferData]] ◎ Let arrayBufferData be O.[[ArrayBufferData]].
- %arrayBufferByteLength ~LET %O.[[ArrayBufferByteLength]] ◎ Let arrayBufferByteLength be O.[[ArrayBufferByteLength]].
- ! `DetachArrayBuffer$A( %O ) ◎ Perform ! DetachArrayBuffer(O).
- ~RET 次のように設定された新たな `ArrayBuffer$I ~obj(`現在の~Realm~Record$内に作成される) ⇒# [[ArrayBufferData]] 内部~slot ~SET %arrayBufferData, [[ArrayBufferByteLength]] 内部~slot ~SET %arrayBufferByteLength ◎ Return a new ArrayBuffer object (created in the current Realm Record) whose [[ArrayBufferData]] internal slot value is arrayBufferData and whose [[ArrayBufferByteLength]] internal slot value is arrayBufferByteLength.
6.3.7. `ValidateAndNormalizeHighWaterMark( highWaterMark )^A
- %highWaterMark ~SET ? `ToNumber$A( %highWaterMark ) ◎ Set highWaterMark to ? ToNumber(highWaterMark).
-
~IF[ %highWaterMark ~EQ `NaN^b ]~OR[ %highWaterMark ~LT `0^b ] ⇒ ~THROW `TypeError^b ◎ If highWaterMark is NaN or highWaterMark < 0, throw a RangeError exception.
+∞ は妥当な`限界水位$として明示的に許容される。 それは、`背圧$が決して適用されないようにする。 ◎ +∞ is explicitly allowed as a valid high water mark. It causes backpressure to never be applied.
- ~RET %highWaterMark ◎ Return highWaterMark.
6.3.8. `MakeSizeAlgorithmFromSizeFunction( size )^A
- ~IF[ %size ~EQ ~undefined ] ⇒ ~RET `1^b を返す~algo ◎ If size is undefined, return an algorithm that returns 1.
- ~IF[ ! `IsCallable$A( %size ) ~EQ ~false ] ⇒ ~THROW `TypeError^b ◎ If ! IsCallable(size) is false, throw a TypeError exception.
-
~RET 引数 ( %chunk ) をとり,次の手続きを遂行する~algo: ◎ Return an algorithm that performs the following steps, taking a chunk argument:
- ~RET ? `Call$A( %size, ~undefined, « %chunk » ) ◎ Return ? Call(size, undefined, « chunk »).
7. 各種~大域~prop
次の構築子が同じ名前の~data~propとして`大域~obj$上に公開され~MUST: ◎ The following constructors must be exposed on the global object as data properties of the same name:
- `ReadableStream$C
- `WritableStream$C
- `TransformStream$C
- `ByteLengthQueuingStrategy$C
- `CountQueuingStrategy$C
これらの~propの属性は、 { [[Writable]]: ~true, [[Enumerable]]: ~false, [[Configurable]]: ~true } にされ~MUST。 ◎ The attributes of these properties must be { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }.
次の各種~classは、独立に有用になることはないので,特に 公開されない ⇒# `ReadableStreamDefaultReader$C, `ReadableStreamBYOBReader$C, `ReadableStreamDefaultController$C, `ReadableByteStreamController$C, `WritableStreamDefaultWriter$C, `WritableStreamDefaultController$C, `TransformStreamDefaultController$C ◎ The ReadableStreamDefaultReader, ReadableStreamBYOBReader, ReadableStreamDefaultController, ReadableByteStreamController, WritableStreamDefaultWriter, WritableStreamDefaultController, and TransformStreamDefaultController classes are specifically not exposed, as they are not independently useful.
8. ~streamを作成する例
~INFORMATIVE-DEEPこれまでの例では、~streamを利用する方法に力点を置いていた。 ここでは、 `ReadableStream$C / `WritableStream$C 構築子を利用して,~streamを作成する方法を示す。 ◎ The previous examples throughout the standard have focused on how to use streams. Here we show how to create a stream, using the ReadableStream or WritableStream constructors.
8.1. 下層~push源を伴う可読~stream(背圧~supportなし)
次の関数は、 `WebSocket$I ~instance `HTML$r を包装する可読~streamを作成する。 それは、背圧~合図を~supportしない`~push源$である。 `~push源$に適応させるとき、通例的に,働きを成す大部分は `start()$src 関数にて起きるようにされる。 ◎ The following function creates readable streams that wrap WebSocket instances [HTML], which are push sources that do not support backpressure signals. It illustrates how, when adapting a push source, usually most of the work happens in the start() function.
function makeReadableWebSocketStream(%url, %protocols) { const %ws = new WebSocket(%url, %protocols); %ws.binaryType = `arraybuffer^l; return new ReadableStream({ start(%controller) { %ws.onmessage = %event => %controller.enqueue(%event.data); %ws.onclose = () => %controller.close(); %ws.onerror = () => %controller.error(new Error(`WebSocket に~errorが生じました^l)); }, cancel() { %ws.close(); } }); }
この関数を利用すれば、~web~socket用の可読~streamを作成して,それを任意の可書~streamへ~pipeできるようになる: ◎ We can then use this function to create readable streams for a web socket, and pipe that stream to an arbitrary writable stream:
const %webSocketStream = makeReadableWebSocketStream(`wss://example.com:443/^l, `protocol^l); webSocketStream.pipeTo(%writableStream) .then(() => console.log(`すべての~dataは成功裡に書込されました^l)) .catch(%e => console.error(`何かまずいことが起きたようです^l, %e));
~web~socketをこのように包装する~styleは、~web~socket~messageを,直に`~chunk$として解釈する。 これは、簡便な抽象化になり得る — 例えば、各~web~socket~messageが[ 消費する/形式変換する ]~chunkとして~~意味を成すように[ `可書~stream$/`形式変換~stream$ ]へ`~pipeする$とき。 ◎ This specific style of wrapping a web socket interprets web socket messages directly as chunks. This can be a convenient abstraction, for example when piping to a writable stream or transform stream for which each web socket message makes sense as a chunk to consume or transform.
しかしながら,誰かが “~web~socketに~stream~supportを追加する” ことについて話すときは、代わりに[ 個々の~web~socket~messageを,~streaming方式fで送信する ]ような新たな能力を希望していることが多い — 例えば、~fileを[ そのすべての内容を~client側の記憶域~内に保持する ]ことなく,単独の~message内に転送できるような。 この目標を達成するためには、個々の~web~socket~message自身が `ReadableStream$C ~instanceになれることが求められる。 それは、上の例に示したものではない。 ◎ However, often when people talk about "adding streams support to web sockets", they are hoping instead for a new capability to send an individual web socket message in a streaming fashion, so that e.g. a file could be transferred in a single message without holding all of its contents in memory on the client side. To accomplish this goal, we’d instead want to allow individual web socket messages to themselves be ReadableStream instances. That isn’t what we show in the above example.
背景情報については、 この論点 を見よ。 ◎ For more background, see this discussion.
8.2. 下層~push源を伴う可読~stream(背圧~supportあり)
次の関数は、 “背圧~socket” を包装する`可読~stream$を返す — 背圧~socketは、~web~socketと同じ~APIを持つ仮説上の~objであるが,[ `readStop^m / `readStart^m ]~methodにより,~dataの流れを[ 静止する/再開する ]能も供する。 この例は、そうすることで,背圧を~supportする`下層~源$にそれを適用する方法を示すものになる。 ◎ The following function returns readable streams that wrap "backpressure sockets," which are hypothetical objects that have the same API as web sockets, but also provide the ability to pause and resume the flow of data with their readStop and readStart methods. In doing so, this example shows how to apply backpressure to underlying sources that support it.
function makeReadableBackpressureSocketStream(%host, %port) { const %socket = createBackpressureSocket(%host, %port); return new ReadableStream({ start(%controller) { %socket.ondata = %event => { %controller.enqueue(%event.data); if (%controller.desiredSize <= 0) { /* 内部~queueは満杯なので,下層~源へ背圧~合図を伝播させる。 ◎ The internal queue is full, so propagate the backpressure signal to the underlying source. */ socket.readStop(); } }; %socket.onend = () => %controller.close(); %socket.onerror = () => %controller.error(new Error(`~socketに~errorが生じました^l)); }, pull() { /* 内部~queueが空になったが,~streamの消費器は まだ更なる~dataを求めている場合に~callされる。 その場合、以前に静止していたなら~dataの流れを再開始する。 ◎ This is called if the internal queue has been emptied, but the stream’s consumer still wants more data. In that case, restart the flow of data if we have previously paused it. */ %socket.readStart(); }, cancel() { %socket.close(); } }); }
この関数を利用すれば、~web~socketのときと同じ仕方で,そのような “背圧~socket” 用の可読~streamを作成できるようになる。 しかしながら,この場合には、[ ~socketが生産するほど高速には~dataを受容できないような行先へ~pipeされたとき ], あるいは[ しばらくの間~streamから読取することなく放置したとき ]は,[ 背圧~合図がその~socketに向けて送信される ]ことになる。 ◎ We can then use this function to create readable streams for such "backpressure sockets" in the same way we do for web sockets. This time, however, when we pipe to a destination that cannot accept data as fast as the socket is producing it, or if we leave the stream alone without reading from it for some time, a backpressure signal will be sent to the socket.
8.3. 下層~push源を伴う可読~byte~stream(背圧~supportなし)
次の関数は、仮説上の UDP ~socket~APIを包装する`可読~byte~stream$を返す — それは、 POSIX `select(2)^c ~system~callを想起するよう意味された,~promiseを返す `select2()^c ~methodを含む。 ◎ The following function returns readable byte streams that wraps a hypothetical UDP socket API, including a promise-returning select2() method that is meant to be evocative of the POSIX select(2) system call.
UDP ~protocolには組込みの背圧~supportはないので、 `desiredSize$rbsc が与える背圧~合図は無視される。 ~streamは、~socketからの~dataが可用になったが,開発者からはまだ要請されていないときには、~streamの`内部~queue$に~enqueueして,~kernel空間の~queueから溢れないようにすることも確保する。 ◎ Since the UDP protocol does not have any built-in backpressure support, the backpressure signal given by desiredSize is ignored, and the stream ensures that when data is available from the socket but not yet requested by the developer, it is enqueued in the stream’s internal queue, to avoid overflow of the kernel-space queue and a consequent loss of data.
これには、`消費器$と~streamとの間の相互作用について興味を引く帰結がある。 消費器が~socketが生産するほど高速に~dataを読取しない場合、`~chunk$たちは,不定期の間~streamの`内部~queue$に残り続ける。 その場合,`~BYOB読取器$を利用すると,~dataを~streamの内部~queueから開発者が給する~bufferへ移動するときに,余分な複製が生じることになる。 一方で,消費器が~dataを十分~素早く消費した場合、`~BYOB読取器$においては, 開発者から給される~bufferへ複製なしに直に読取できるようになる。 ◎ This has some interesting consequences for how consumers interact with the stream. If the consumer does not read data as fast as the socket produces it, the chunks will remain in the stream’s internal queue indefinitely. In this case, using a BYOB reader will cause an extra copy, to move the data from the stream’s internal queue to the developer-supplied buffer. However, if the consumer consumes the data quickly enough, a BYOB reader will allow zero-copy reading directly into developer-supplied buffers.
(この例より複雑な~version — `desiredSize$rbsc を利用して[ 帯域外の,背圧を合図する仕組み ](例えば,~socketに向けて ~dataの送信~rateを調整するような~messageを送信するなど)を伝えるなど — も~~想定できるが、それについては,読者への演習に残しておく。) ◎ (You can imagine a more complex version of this example which uses desiredSize to inform an out-of-band backpressure signaling mechanism, for example by sending a message down the socket to adjust the rate of data being sent. That is left as an exercise for the reader.)
const %DEFAULT_CHUNK_SIZE = 65536;
function makeUDPSocketStream(%host, %port) {
const %socket = createUDPSocket(%host, %port);
return new ReadableStream({
type: `bytes^l,
start(%controller) {
readRepeatedly().catch(%e => %controller.error(%e));
function readRepeatedly() {
return %socket.select2().then(() => {
/*
%socket は可読になり得るので、処理待ちの~BYOB要請がないときでも、両~事例とも取扱う必要がある。
◎
Since the socket can become readable even when there’s no pending BYOB requests, we need to handle both cases.
*/
let %bytesRead;
if (%controller.byobRequest) {
const %v = %controller.byobRequest.view;
%bytesRead = %socket.readInto(%v.buffer, %v.byteOffset, v.byteLength);
%controller.byobRequest.respond(%bytesRead);
} else {
const %buffer = new ArrayBuffer(%DEFAULT_CHUNK_SIZE);
%bytesRead = %socket.readInto(buffer, 0, %DEFAULT_CHUNK_SIZE);
%controller.enqueue(new Uint8Array(%buffer, 0, %bytesRead));
}
if (%bytesRead === 0) {
%controller.close();
return;
}
return readRepeatedly();
});
}
},
cancel() {
%socket.close();
}
});
}
この関数から返される `ReadableStream$C ~instanceは、今や,前に示したすべての便益と但し書きを伴うような `~BYOB読取器$を配給できる。 ◎ ReadableStream instances returned from this function can now vend BYOB readers, with all of the aforementioned benefits and caveats.
8.4. 下層~pull源を伴う可読~stream
次の関数は、(それ自身 直に C 言語の[ `fopen()^m, `fread()^m, `fclose()^m ]組みへ対応付けている) Node.js file system API の各部を包装する,`可読~stream$を返す。 ~fileは `~pull源$の典型~例である。 `~push源$を伴う例とは対照的に、ここでの働きを成す大部分は、 `start()$src 関数の開始時ではなく, `pull()$src 関数~内でその時々に起きることに注意。 ◎ The following function returns readable streams that wrap portions of the Node.js file system API (which themselves map fairly directly to C’s fopen, fread, and fclose trio). Files are a typical example of pull sources. Note how in contrast to the examples with push sources, most of the work here happens on-demand in the pull() function, and not at startup time in the start() function.
const %fs = require(`pr/fs^l); // https://github.com/jden/pr const %CHUNK_SIZE = 1024; function makeReadableFileStream(filename) { let %fd; let %position = 0; return new ReadableStream({ start() { return %fs .open(%filename, `r^l) .then(%result => { %fd = %result; }); }, pull(%controller) { const %buffer = new ArrayBuffer(%CHUNK_SIZE); return %fs .read(%fd, %buffer, 0, %CHUNK_SIZE, %position) .then(%bytesRead => { if (%bytesRead === 0) { return %fs.close(%fd).then(() => %controller.close()); } else { %position += %bytesRead; %controller.enqueue(new Uint8Array(%buffer, 0, %bytesRead)); } }); }, cancel() { return %fs.close(%fd); } }); }
これを利用すれば、前に~socketに対しできたときとちょうど~~同じく,~file用の可読~streamを作成して利用できるようになる。 ◎ We can then create and use readable streams for files just as we could before for sockets.
8.5. 下層~pull源を伴う可読~byte~stream
次の関数は、 Node.js file system API を再度~利用して,~fileを複製することなく効率的に読取できるようにする,`可読~byte~stream$を返す。 それは、予め決定-済みの~chunk~size 1024 を利用する代わりに,開発者から給された~bufferを埋めようと試みることで、全部的~制御を可能にする。 ◎ The following function returns readable byte streams that allow efficient zero-copy reading of files, again using the Node.js file system API. Instead of using a predetermined chunk size of 1024, it attempts to fill the developer-supplied buffer, allowing full control.
const %fs = require(`pr/fs^l); // https://github.com/jden/pr
const DEFAULT_CHUNK_SIZE = 1024;
function makeReadableByteFileStream(%filename) {
let %fd;
let %position = 0;
return new ReadableStream({
type: `bytes^l,
start() {
return %fs.open(%filename, `r^l).then(%result => {
%fd = %result;
});
},
pull(%controller) {
/*
消費器が既定の読取器を利用していても,自動割当て特色機能は、~bufferを割当てて,それを `byobRequest$rbsc を介して渡してくれる。
◎
Even when the consumer is using the default reader, the auto-allocation feature allocates a buffer and passes it to us via byobRequest.
*/
const %v = %controller.byobRequest.view;
return %fs
.read(%fd, %v.buffer, %v.byteOffset, %v.byteLength, %position)
.then(%bytesRead => {
if (%bytesRead === 0) {
return %fs.close(%fd).then(() => %controller.close());
} else {
%position += %bytesRead;
%controller.byobRequest.respond(%bytesRead);
}
});
},
cancel() {
return %fs.close(%fd);
},
autoAllocateChunkSize: DEFAULT_CHUNK_SIZE
});
}
これを使えば、返された `ReadableStream$C 用の`~BYOB読取器$を作成して利用できるようになる。 一方で、それを[ 通例的~なものと同じ,単純かつ汎用的な方式 ]で利用して,`既定の読取器$を作成することもできる。 [ 低levelの,ここに示す`下層~byte源$に対する~byteの追跡 ]と[ より高levelな,~chunkに基づく`既定の読取器$による消費 ]との間の適応は、すべて,~stream実装により自動的に~careされる。 `autoAllocateChunkSize^m ~optionを介する自動割当て特色機能は、[ `§下層~push源を伴う可読~byte~stream(背圧~supportなし)$ のように手動的に分岐する ]のに比して,必要な~code量も少なく済ませられる。 ◎ With this in hand, we can create and use BYOB readers for the returned ReadableStream. But we can also create default readers, using them in the same simple and generic manner as usual. The adaptation between the low-level byte tracking of the underlying byte source shown here, and the higher-level chunk-based consumption of a default reader, is all taken care of automatically by the streams implementation. The auto-allocation feature, via the autoAllocateChunkSize option, even allows us to write less code, compared to the manual branching in §8.3 A readable byte stream with an underlying push source (no backpressure support).
8.6. 背圧や成功の合図を伴わない可書~stream
次の関数は、 `WebSocket$I `HTML$r を包装する`可書~stream$を返す。 ~web~socketは[ 所与の~dataの`~chunk$が いつ成功裡に送信されたか ]を伝える仕方を供さない(扱いにくい `bufferedAmount$m の~pollingを行わない限り — それについては,読者への演習に残しておく)。 そのようなわけで、この可書~streamは,その`生産器$に[ 正確0な背圧~合図や 書込の成否 ]を通信する能を持たない。 すなわち、その`書込器$の `write()$dw ~method / `ready$dw 取得子 から返される~promiseは、常に即時に充足されることになる。 ◎ The following function returns a writable stream that wraps a WebSocket [HTML]. Web sockets do not provide any way to tell when a given chunk of data has been successfully sent (without awkward polling of bufferedAmount, which we leave as an exercise to the reader). As such, this writable stream has no ability to communicate accurate backpressure signals or write success/failure to its producers. That is, the promises returned by its writer’s write() method and ready getter will always fulfill immediately.
function makeWritableWebSocketStream(%url, %protocols) {
const %ws = new WebSocket(%url, %protocols);
return new WritableStream({
start(%controller) {
%ws.onerror = () => {
%controller.error(new Error(`WebSocket に~errorが生じました^l));
%ws.onclose = null;
};
%ws.onclose = () => {
%controller.error(new Error(`接続は不意に~serverにより~closeされました^l));
}
return new Promise(%resolve => %ws.onopen = %resolve);
},
write(%chunk) {
%ws.send(%chunk);
/*
即時に返る
— ~web~socketでは,書込がいつ完了するかを伝える容易な仕方はないので。
◎
Return immediately, since the web socket gives us no easy way to tell when the write completes.
*/
},
close() {
return closeWS(1000);
});
},
abort(%reason) {
return closeWS(4000, %reason && %reason.message);
},
});
function closeWS(%code, %reasonString) {
return new Promise((%resolve, %reject) => {
%ws.onclose = %e => {
if (%e.wasClean) {
%resolve();
} else {
%reject(new Error(`接続は~cleanに~closeされませんでした^l));
}
};
%ws.close(%code, %reasonString);
});
}
}
この関数を利用すれば、~web~socket用の可書~streamを作成して,任意の可読~streamをそれに~pipeできるようになる: ◎ We can then use this function to create writable streams for a web socket, and pipe an arbitrary readable stream to it:
const %webSocketStream = makeWritableWebSocketStream( `wss://example.com:443/^l, `protocol^l); readableStream.pipeTo(%webSocketStream) .then(() => console.log(`すべての~dataは成功裡に書込されました^l)) .catch(%e => console.error(`何かまずいことが起きたようです^l, %e));
注記: この~styleで~web~socketを~streamの中に包装することについては、 前述の注記 を見よ。 ◎ See the earlier note about this style of wrapping web sockets into streams.
8.7. 背圧や成功の合図を伴う可書~stream
次の関数は、(それ自身 直に C 言語の[ `fopen^m, `fwrite^m, `fclose^m ]組みへ対応付けている) Node.js file system API の各部を包装する,`可書~stream$を返す。 その~APIは、所与の書込が成功したときにそれを伝える仕方を供するので、この~streamは,個々の書込の成否も込みで,`背圧$合図を通信できる。 ◎ The following function returns writable streams that wrap portions of the Node.js file system API (which themselves map fairly directly to C’s fopen, fwrite, and fclose trio). Since the API we are wrapping provides a way to tell when a given write succeeds, this stream will be able to communicate backpressure signals as well as whether an individual write succeeded or failed.
const %fs = require(`pr/fs^l); // https://github.com/jden/pr function makeWritableFileStream(%filename) { let %fd; return new WritableStream({ start() { return %fs.open(%filename, `w^l).then(%result => { %fd = %result; }); }, write(%chunk) { return %fs.write(%fd, %chunk, 0, %chunk.length); }, close() { return %fs.close(%fd); }, abort() { return %fs.close(%fd); } }); }
この関数を利用すれば、~file用の可書~streamを作成して,個々の~data`~chunk$を書込できるようになる: ◎ We can then use this function to create a writable stream for a file, and write individual chunks of data to it:
const %fileStream = makeWritableFileStream(`/example/path/on/fs.txt^l); const %writer = %fileStream.getWriter(); %writer.write(`~streamするか, しないか、\n^l); %writer.write(`それが~~問題だ。\n^l); %writer.close() .then( () => console.log( `~chunkたちは書込され, ~streamは成功裡に~closeされました^l )) .catch(%e => console.error(%e));
特定0の `fs.write^m ~callにて時間がかかる場合、返される~promiseは,~~後に充足されることになることに注意。 当面の間は,追加の書込を~queue-upできる — それらは~streamの内部~queueに格納される。 この~queueにおける`~chunk$たちの累積により、~streamは, `ready$dw 取得子が処理待ち~promiseを返すように変化し得る — それは、~streamの`生産器$に[ 可能なら,手を止めて書込みを停止することで、便益を得ることになる ]ことを合図する。 ◎ Note that if a particular call to fs.write takes a longer time, the returned promise will fulfill later. In the meantime, additional writes can be queued up, which are stored in the stream’s internal queue. The accumulation of chunks in this queue can change the stream to return a pending promise from the ready getter, which is a signal to producers that they would benefit from backing off and stopping writing, if possible.
この事例においては、可書~streamが書込を~queue-upする仕方が,とりわけ重要になる
—
`fs.write^m にて文書化されている
ように:
[promise] を待機することなく,同じ~file上で
`fs.write^m を複数回 利用することは安全でない
ので。
しかしながら、 `makeWritableFileStream^m 関数を書くときは,それについて心配する必要はない
— ~stream実装が,[
`下層~槽$の `write()$snk ~methodは,[
以前の~callにより返された~promiseがあれば,それが充足される
]まで~callされない
]ことを保証してくれる。
◎
The way in which the writable stream queues up writes is especially important in this case, since as stated in the documentation for fs.write, "it is unsafe to use fs.write multiple times on the same file without waiting for the [promise]." But we don’t have to worry about that when writing the makeWritableFileStream function, since the stream implementation guarantees that the underlying sink’s write() method will not be called until any promises returned by previous calls have fulfilled!
8.8. 同じ下層~資源を包装する { 可読, 可書 } ~stream~pair
次の関数は `{ readable, writable }^c の形による~objを返す — `readable^m ~propは可読~streamを, `writable^m ~propは可書~streamを包含していて、両~streamとも同じ下層~web~socket資源を包装するような。 これは、本質的には,[ `§下層~push源を伴う可読~stream(背圧~supportなし)$ ]と[ `§背圧や成功の合図を伴わない可書~stream$ ]を組合せる。 ◎ The following function returns an object of the form { readable, writable }, with the readable property containing a readable stream and the writable property containing a writable stream, where both streams wrap the same underlying web socket resource. In essence, this combines §8.1 A readable stream with an underlying push source (no backpressure support) and §8.6 A writable stream with no backpressure or success signals.
~JS~classを利用して、再利用-可能な `下層~槽$/`下層~源$ の抽象化を作成する方法を~~示す: ◎ While doing so, it illustrates how you can use JavaScript classes to create reusable underlying sink and underlying source abstractions.
function streamifyWebSocket(%url, %protocol) { const %ws = new WebSocket(%url, %protocols); %ws.binaryType = `arraybuffer^l; return { readable: new ReadableStream(new WebSocketSource(%ws)), writable: new WritableStream(new WebSocketSink(%ws)) }; } class WebSocketSource { constructor(%ws) { this._ws = %ws; } start(controller) { this._ws.onmessage = %event => %controller.enqueue(%event.data); this._ws.onclose = () => %controller.close(); this._ws.addEventListener(`error^l, () => { %controller.error(new Error(`WebSocket に~errorが生じました^l)); }); } cancel() { this._ws.close(); } } class WebSocketSink { constructor(%ws) { this._ws = %ws; } start(%controller) { this._ws.onclose = () => { %controller.error(new Error(`接続は不意に~serverにより~closeされました^l)); } this._ws.addEventListener(`error^l, () => { %controller.error(new Error(`WebSocket に~errorが生じました^l)); this._ws.onclose = null; }); return new Promise(%resolve => this._ws.onopen = %resolve); } write(%chunk) { this._ws.send(%chunk); } close() { return this._closeWS(1000); } abort(%reason) { return this._closeWS(4000, %reason && %reason.message); } _closeWS(%code, %reason) { return new Promise((%resolve, %reject) => { this._ws.onclose = %e => { if (%e.wasClean) { %resolve(); } else { %reject(new Error(`接続は~cleanに~closeされませんでした^l)); } }; this._ws.close(code, reasonString); }); } }
この関数で作成された~objを利用すれば、標準~stream~APIを利用して,遠隔の~web~socketと通信できるようになる: ◎ We can then use the objects created by this function to communicate with a remote web socket, using the standard stream APIs:
const %streamyWS = streamifyWebSocket(`wss://example.com:443/^l, `protocol^l); const %writer = %streamyWS.writable.getWriter(); const %reader = %streamyWS.readable.getReader(); %writer.write(`どうも、^l); %writer.write(`web socket さん。^l); %reader.read().then(({ %value, %done }) => { console.log(`こちらこそ、どうもです:^l, %value); });
このように設定しておけば、[ `readable^m 側を取消すと,暗黙的に `writable^m 側が~closeされ ],同様に[ `writable^m 側を~closeする/中止すると,暗黙的に `readable^m 側が~closeされる ]ようになることに注意。 ◎ Note how in this setup canceling the readable side will implicitly close the writable side, and similarly, closing or aborting the writable side will implicitly close the readable side.
注記: この~styleで~web~socketを~streamの中に包装することについては、 前述の注記 を見よ。 ◎ See the earlier note about this style of wrapping web sockets into streams.
8.9. ~template内の~tagを置換する形式変換~stream
~dataが成す~stream上の~tagたちを変数に置換sすることが有用になることは多い
— 置換される必要がある部品たちが、総~data~sizeに比較して小さい所では。
この例は、それを行う単純な仕方を提示する。
それは、文字列を文字列に~mapする
— 例えば,
`Time: {{time}} Message: {{message}}^l
の様な~templateを
`Time: 15:36 Message: hello^l
の様に形式変換して(
`LipFuzzTransformer^C には、
%substitutions ~parameter内に
{ time: `15:36^l, message: `hello^l }
が渡されたとする)。
◎
It’s often useful to substitute tags with variables on a stream of data, where the parts that need to be replaced are small compared to the overall data size. This example presents a simple way to do that. It maps strings to strings, transforming a template like "Time: {{time}} Message: {{message}}" to "Time: 15:36 Message: hello" assuming that { time: "15:36", message: "hello" } was passed in the substitutions parameter to LipFuzzTransformer.
この例は、[ さらに~dataが受信されるまで,~chunkを形式変換できないような、部分的な~data ]を包含する状況に~~対処する仕方も例示する。 この事例では、部分的な~template~tagは、~tagの終端が見出されるか,~streamの終端に達するまで, `partialChunk^c ~instance変数~内に累積されることになる。 ◎ This example also demonstrates one way to deal with a situation where a chunk contains partial data that cannot be transformed until more data is received. In this case, a partial template tag will be accumulated in the partialChunk instance variable until either the end of the tag is found or the end of the stream is reached.
class LipFuzzTransformer { constructor(%substitutions) { this.substitutions = %substitutions; this.partialChunk = ""; this.lastIndex = undefined; } transform(%chunk, %controller) { %chunk = this.partialChunk + %chunk; this.partialChunk = ""; /* `lastIndex^c は、最後の置換s後の,最初の文字の~index ◎ lastIndex is the index of the first character after the last substitution. */ this.lastIndex = 0; %chunk = %chunk.replace(/\{\{([a-zA-Z0-9_-]+)\}\}/g, this.replaceTag.bind(this)); /* 文字列の終端にある不完全な~template用の正規表現 ◎ Regular expression for an incomplete template at the end of a string. */ const %partialAtEndRegexp = /\{(\{([a-zA-Z0-9_-]+(\})?)?)?$/g; /* すでに置換sされた文字は見ないようにする ◎ Avoid looking at any characters that have already been substituted. */ %partialAtEndRegexp.lastIndex = this.lastIndex; this.lastIndex = undefined; const %match = partialAtEndRegexp.exec(%chunk); if (%match) { this.partialChunk = %chunk.substring(%match.index); %chunk = %chunk.substring(0, %match.index); } %controller.enqueue(%chunk); } flush(%controller) { if (this.partialChunk.length > 0) { %controller.enqueue(this.partialChunk); } } replaceTag(%match, %p1, %offset) { let %replacement = this.substitutions[%p1]; if (%replacement === undefined) { %replacement = ""; } this.lastIndex = %offset + %replacement.length; return %replacement; } }
この事例では、~classとして `TransformStream$C 構築子に渡される,`形式変換器$を定義する。 これは、追跡する~instance~dataがあるときに,有用になる。 ◎ In this case we define the transformer to be passed to the TransformStream constructor as a class. This is useful when there is instance data to track.
この~classは、次の様な~codeに利用されることになる: ◎ The class would be used in code like:
const %data = { %userName, %displayName, %icon, %date }; const %ts = new TransformStream(new LipFuzzTransformer(%data)); %fetchEvent.respondWith( fetch(%fetchEvent.request.url).then(%response => { const %transformedBody = %response.body /* ~binaryに符号化された応答~本体を文字列に復号する ◎ Decode the binary-encoded response to string */ .pipeThrough(new TextDecoderStream()) /* %LipFuzzTransformer を適用する ◎ Apply the LipFuzzTransformer */ .pipeThrough(%ts) /* 形式変換された文字列を符号化する ◎ Encode the transformed string */ .pipeThrough(new TextEncoderStream()); return new Response(%transformedBody); }) );
単純にするため、 `LipFuzzTransformer^C は,~text置換sに際し~escapeしていない。 現実の応用においては、文脈に応じて~escapeする~template~systemの方が,~securityや堅牢性に関して良実践になる。 ◎ For simplicity, LipFuzzTransformer performs unescaped text substitutions. In real applications, a template system that performs context-aware escaping is good practice for security and robustness.
8.10. 同期~mapper関数から作成される形式変換~stream
次の関数は、通常は `Array.prototype.map$c に渡すような型の同期的な “~mapper” 関数から,新たな `TransformStream$C ~instanceを作成-可能にする。 それは、自明な形式変換に対しても,~APIは簡潔になることを例示する。 ◎ The following function allows creating new TransformStream instances from synchronous "mapper" functions, of the type you would normally pass to Array.prototype.map. It demonstrates that the API is concise even for trivial transforms.
function mapperTransformStream(%mapperFunction) { return new TransformStream({ transform(%chunk, %controller) { %controller.enqueue(mapperFunction(%chunk)); } }); }
この関数を利用すれば、すべての入力を大文字~化する `TransformStream$C を作成できる: ◎ This function can then be used to create a TransformStream that uppercases all its inputs:
const %ts = mapperTransformStream(%chunk => %chunk.toUpperCase());
const %writer = %ts.writable.getWriter();
const %reader = %ts.readable.getReader();
writer.write(`No need to shout^l);
/*
これは `NO NEED TO SHOUT^l を~logする:
◎
Logs "NO NEED TO SHOUT":
*/
reader.read().then(({ value }) => console.log(value));
同期的な形式変換は、背圧~自体は決して生じさせず,背圧がないときに限り ~chunkたちを形式変換するので、資源が浪費されることはない。 ◎ Although a synchronous transform never causes backpressure itself, it will only transform chunks as long as there is no backpressure, so resources will not be wasted.
例外が生じたときは、~streamを自然な仕方で~errorにする: ◎ Exceptions error the stream in a natural way:
const %ts = mapperTransformStream(%chunk => JSON.parse(%chunk));
const %writer = %ts.writable.getWriter();
const %reader = %ts.readable.getReader();
writer.write(`[1, ^l);
/*
`SyntaxError^b を重ねて~logする:
◎
Logs a SyntaxError, twice:
*/
%reader.read().catch(%e => console.error(%e));
%writer.write(`{}^l).catch(%e => console.error(%e));
表記規約
この仕様は、 `INFRA$r に依存する。 ◎ This specification depends on the Infra Standard. [INFRA]
この仕様は、その解釈-時に利用するべき~algo表記規約として, `ECMASCRIPT$r によるそれにごく近いものを利用する(以下に挙げる例外は別として)。 特に,ここに指定される各種~objは、`組込みの~obj$として扱われるべきである。 例えば,それらの[ `name^c, `length^c ]~propは、その仕様に述べるように導出される。 また、既定の~prop記述子 値や, [ 与えられていない / ~undefined / 余剰な ]引数の扱いについても同様とする。 ◎ This specification uses algorithm conventions very similar to those of [ECMASCRIPT], whose rules should be used to interpret it (apart from the exceptions enumerated below). In particular, the objects specified here should be treated as built-in objects. For example, their name and length properties are derived as described by that specification, as are the default property descriptor values and the treatment of missing, undefined, or surplus arguments.
簡潔にするため、以下の仕方で, `ECMASCRIPT$r から外れた表記規約も用いている。 ~ECMAScript自身の表記規約が,これらの仕方で発展するものと希望されている(また,漠然と計画されている)。 ◎ We also depart from the [ECMASCRIPT] conventions in the following ways, mostly for brevity. It is hoped (and vaguely planned) that the conventions of ECMAScript itself will evolve in these ways.
- 節の見出しに接頭された `new^c は、構築子を定義していることを指示する。 そこでは、~algoの開始-前に, `NewTarget^b が検査されることになるものと見做される。 ◎ We prefix section headings with new to indicate they are defining constructors; when doing so, we assume that NewTarget will be checked before the algorithm starts.
- いくつかの事例では,既定の引数を表す記法として `= {}^c が用いられる。 これは、 ~undefined は(引数が供されなかった場合の暗黙的 ~undefined も含め),~algoの開始-前に[ `ObjectCreate$A( `~ObjectPrototype$ ) により新たな~objが作成された ]かのように扱われることを意味する。 (この~objは,さらに分割代入されることもある — 下の分割代入の表記規約と組合されたときには。) ◎ We use the default argument notation = {} in a couple of cases, meaning that before the algorithm starts, undefined (including the implicit undefined when no argument is provided) is instead treated as a new object created as if by ObjectCreate(%ObjectPrototype%). (This object may then be destructured, if combined with the below destructuring convention.)
- 関数/~method の宣言には、分割代入( `destructuring^en )記法が利用される — そこでは、~algoの開始-前に, `DestructuringAssignmentEvaluation$Ax が適切に遂行されるものと見做される。 ◎ We use destructuring notation in function and method declarations, and assume that DestructuringAssignmentEvaluation was performed appropriately before the algorithm starts.
- "~this" は "~this 値" の略記である。 ◎ We use "this" instead of "this value".
-
~ECMAScript仕様より高levelで~promise上に演算するときに `PROMISES-GUIDE$r による各種 略記~句を利用する:
- 新たな~promise
- 〜で解決される~promise
- 〜で却下される~promise
- 〜で~promiseを解決する
- 〜で~promiseを却下する
- 〜で~promiseを変形-する
- ~promiseの充足-時には…
- ~promiseの却下-時には…
`ECMASCRIPT$r と同様,言うまでもなく、すべての~numberは 倍精度~浮動小数点による値で表現され,それらに対し遂行される すべての算術~演算は 標準の仕方で行われ~MUSTことに注意。 ◎ It’s also worth noting that, as in [ECMASCRIPT], all numbers are represented as double-precision floating point values, and all arithmetic operations performed on them must be done in the standard way for such values.
【 上述の~ECMAScript仕様の表記規約のうち,この仕様にて利用されている主なものを、以下に挙げる(この訳による補完): 】
- “~Assert: …” は、いわゆる表明を表す。 (~~要約:) 暗黙的な不変則を明示的に示して ~algoの明確化を図るものであり、~algoの意味論に要件を追加するものではない。
- `中途完了@ ( abrupt completion ) — (引用) 中途完了とは、演算の完了に伴われる [[type]] 値が normal 以外であることを意味する。
-
抽象~演算の前に置かれる記号 "!", "?" の意味は、 ~algo表記規約 に定義されている。 大雑把に述べれば:
- "! `AbstractOp^A(…)" という表記は、そこでの `AbstractOp^A の~callは決して`中途完了$にならないことを表す。
- "? `AbstractOp^A(…)" という表記は、`中途完了$になり得るため,例外が投出され得ることを表す。
-
`~List@, `~Record@ 型は、 The List and Record Specification Types ( “仕様が規定する~modelにのみ~~存在する型” )に定義されている:
- `~List$ は、順序~付けられた値たちからなる~listを表す。
- "« %A, %B, … »" のような表記は、~literalによる`~List$の初期化を表す。
- `~Record$ は、名前を持ついくつかの~fieldからなる順序のない集合(すなわち, ~map )を表す。
- "`~Record$ { … }" のような表記は、~literalによる `~Record$ の初期化を表す。
-
"
%args => %code
" のような表記は、 %args を引数に %code を実行する無名~関数を表す( arrow function )。 - `class^c — Class Definitions
-
以下の各種 抽象~演算は、`ECMASCRIPT$r 仕様にて定義される:
- `Call$Ax
- `Construct$Ax
- `CreateArrayFromList$Ax
- `CreateDataProperty$Ax
- `CreateIterResultObject$Ax
- `Get$Ax
- `GetV$Ax
- `Invoke$Ax
- `IsCallable$Ax
- `IsInteger$Ax
- `IsPropertyKey$Ax
- `ObjectCreate$Ax
- `ToBoolean$Ax
- `ToNumber$Ax
- `ToString$Ax
- `Type$Ax
- `CopyDataBlockBytes$Ax
- `CloneArrayBuffer$Ax
- `IsDetachedBuffer$Ax
- `DetachArrayBuffer$Ax
謝辞
次に挙げる方々のみならず、この仕様に寄与された すべての方々に感謝する。 彼らの協力なくしては、この仕様は成し得なかったであろう:
The editors would like to thank Anne van Kesteren, AnthumChris, Arthur Langereis, Ben Kelly, Bert Belder, Brian di Palma, Calvin Metcalf, Dominic Tarr, Ed Hager, Forbes Lindesay, Forrest Norvell, Gorgi Kosev, 贺师俊 (hax), Isaac Schlueter, isonmad, Jake Archibald, Jake Verbaten, Janessa Det, Jens Nockert, Lennart Grahl, Mangala Sadhu Sangeet Singh Khalsa, Marcos Caceres, Marvin Hagemeister, Mattias Buelens, Michael Mior, Mihai Potra, Romain Bellessort, Simon Menke, Stephen Sugden, Surma, Tab Atkins, Tanguy Krotoff, Thorsten Lorenz, Till Schneidereit, Tim Caswell, Trevor Norris, tzik, Will Chan, Youenn Fablet, 平野裕 (Yutaka Hirano), and Xabier Rodríguez for their contributions to this specification. Community involvement in this specification has been above and beyond; we couldn’t have done it without you.
This standard is written by Adam Rice (Google, ricea@chromium.org), Domenic Denicola (Google, d@domenic.me), and 吉野剛史 (Takeshi Yoshino, Google, tyoshino@chromium.org).
Copyright © 2018 WHATWG (Apple, Google, Mozilla, Microsoft). This work is licensed under a Creative Commons Attribution 4.0 International License.