1. 序論
◎非規範的~web~platformの相当部分は、~streaming~data上に築かれている: すなわち,~dataは、 全部を~memory内に読取ることなく,増分的な流儀で、 作成され, 処理され, 消費される。 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$I ~instanceとして公開する。 より一般には,~platformは、 ~streamとして表出される抽象-化を待っている~streamingに満ちている: ~multimedia~stream, ~file~stream, 大域~obj間の通信, 等々… — すべてを~memory内に~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する。 ~swの `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.
【この訳に特有な表記規約】
◎表記記号尚、この仕様~自身も~~末尾に自前の`表記規約@#conventions$を備えていることに注意。
`剰余@( %A, %B ) と記された所では、 所与の ( 負でない整数 %A, 正な整数 %B ) に対し, %A を %B で除算したときの剰余を返す。
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 / 読取n可能な~stream)は、 そこから読取れるような,~dataの~sourceを表現する。 言い換えれば、 ~dataは,可読~streamから`~~湧き出る^em。 可読~streamは、 具体的には, `ReadableStream$I ~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は,[ `下層~source@ ( `underlying source^en )と~~呼ばれる,より低~levelな入出力~source ]を包装する。 下層~sourceには、 2 種の型 — `~push~source$と`~pull~source$ — がある。 ◎ 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~source@ は、要請の有無にかかわらず,~dataを~pushしてくるような`下層~source$である。 それは、~dataの流れを 静止させる/再開させる ための仕組みを供することもある。 ~push~sourceの例には,~TCP~socketがある — そこでは、~dataは,~OS~levelから絶えず~pushされ続ける — ~TCP窓~sizeを変更することで制御できるような~rateで。 ◎ 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~source@ は、~dataを得るためには要請を要する`下層~source$である。 ~dataは、同期的に可用になることもあれば (例: ~OSの~memory~bufferに保持されている場合), 非同期的に可用になることもある (例:~diskからの読取nを要する場合)。 ~pull~sourceの例には,~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は、 どちらの型の~sourceも,単独の統一化された~interfaceの背後に包装するように設計されている。 ~web開発者により作成される~stream用の~sourceについては、その実装の詳細は,[ `new ReadableStream()$m 構築子に渡された, `一定の~method, ~propを伴う~obj@#underlying-source-api$ ]により供される。 ◎ 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$たちは、`下層~source$から~streamの中へ~enqueueされる。 ~chunkたちは、~streamの公な~interfaceを介して — 特に、~streamの `getReader()$rs ~methodを利用して獲得した`可読~stream読取器$を利用して — 各回に 1 個ずつ読取れる。 ◎ 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から その公な~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$たちは捨てて, `下層~source$に取消nの仕組みがあればそれを実行する ]ことを指示する。 ◎ 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用の`下層~source$は、 `下層~byte~source@ とも呼ばれる。 `下層~source$が`下層~byte~source$でもあるような`可読~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 / 書込n可能な~stream)は、 そこへ書込めるような,~dataの行先を表現する。 言い換えれば、~dataは,可書~streamへ`~~流れ込む^em。 可書~streamは、 具体的には, `WritableStream$I ~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は, `下層~sink@ ( `underlying sink^en )と呼ばれる,より低~levelな入出力~sinkを包装する。 可書~streamは、[ 一連の書込nを~queueして,下層~sinkに 1 個ずつ送達する ]ことにより,[ 下層~sinkの複階性の一部を抽象-化して見えなくする ]ように働く。 ◎ 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$たちは、 ~streamの公な~interfaceを介して ~streamへ書込まれ, 各回に 1 個ずつ~streamの`下層~sink$に渡される。 ~web開発者により作成される~stream用の~sinkについては、 その実装の詳細は[ `new WritableStream()$m 構築子に渡された, `一定の~method, ~propを伴う~obj@#underlying-sink-api$ ]が供する。 ◎ 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の中へ,その公な~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 する)能も備える。 これは、[ 生産器が 何か不具合があると確信したこと, したがって 以降の書込nは継続されるべきでないこと ]を指示する。 これは、[ `下層~sink$からの通達がなくとも,~streamを~error状態に置く ]ことに加え, ~streamの`内部~queue$内にある すべての書込nを破棄する。 ◎ 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.
具体的には、 どの~objも[ `writable^m, `readable^m ]両~propを伴うならば, 形式変換~streamとして~serveし得る。 しかしながら、 標準な `TransformStream$I ~classが[ 適正に連絡された そのような~pair ]をずっと容易に作成する。 それは、[ 遂行される特定の形式変換n用の~algoを定義する, `形式変換器@ ( `transformer^en )~obj ]を包装する。 ~web開発者により作成される~stream用の`形式変換器$については、 その実装の詳細は,[ `new TransformStream()$m 構築子に渡された, `一定の~method, ~propを伴う~obj@#transformer-api$ ]により供される。 他の仕様は、 `GenericTransformStream$I ~mixinを利用して,同じ[ `writable^m, `readable^m ]~prop~pairを伴うが, 他の~custom~APIを上層に重ねるための~classを作成するかもしれない。 ◎ 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. Other specifications might use the GenericTransformStream mixin to create classes with the same writable/readable property pair but other custom APIs layered on top.
`恒等変換~stream@ ( `identity transform stream^en )は、 形式変換~streamの一種であり, `可書~側$に書込まれた`~chunk$をそのまま`可読~側$に送り込む。 これは、 `様々な局面@#example-transform-identity$で有用になる。 `形式変換器$~objに `transform()$tf ~methodが無いときの既定では、 `TransformStream$I 構築子は, 恒等変換~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の`下層~source$を `元の~source@ ( `original source^en )と呼び、 末尾にある可書~streamの`下層~sink$を `最終~sink@ ( `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鎖を通して後方へ, 最終的に元の~sourceまで通達が伝播され、 元の~sourceに[ ~chunkの生産-を止めるよう伝える ]ことになる。 この,[ 鎖がどの~~程度 高速に~chunkを処理できるかに則って, 元の~sourceからの流れを正常化する処理n ]は、 `背圧@ ( `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.
具体的には、
`元の~source$が~dataを流す~rateは,
%controller.`desiredSize$rsdc
(または
%byteController.`desiredSize$rbsc
)から与えられる値に則って調整できる。
この値は、
`最終~sink$に対応している
%writer.`desiredSize$dw
から導出され,最終~sinkへの`~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の`下層~source$へ送信されることになる。 ◎ 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を下層~sourceから下層~sinkへ直に~~運び続ける ]などの重要な最適化を実装に許容する。 ◎ 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は、[ `下層~source$により~enqueueされたが、 `消費器$からはまだ読取られていない ]ような`~chunk$たちを包含する。 可書~streamの内部~queueは、[ `生産器$により~streamに書込まれ,承認されたが、 まだ`下層~sink$により処理されていない ]ような`~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 [ 限界水位 ~MINUS 合計~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においては、 下層~sourceは,この残り~sizeを[ ~chunk生成を減速させる背圧~通達 ]に利用できる — 残り~sizeを 0 以上に保とうとするために。 可書~streamにおいては、 生産器は,類似に挙動できる — 残り~sizeが負になる前に書込nを避けるために。 ◎ 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.
`具体的には@#qs-api$、 `highWaterMark$qs ~propを伴う どの~JS~objも,[ ~web開発者により作成される~stream用の~queuing策 ]を与える。 ~byte~stream用の `highWaterMark^qs は常に~byte単位になる。 他の~stream用の既定は`~chunk$単位になるが、 ~queuing策~obj内に[ 所与の~chunkに対し その~sizeを返す `size()$qs 関数 ]を含めれば, `highWaterMark^qs に任意な浮動小数点~単位を指定することを許可できる。 ◎ 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$I ~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$I ~classの~instanceである一方、 ~BYOB読取器は, `ReadableStreamBYOBReader$I ~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$I ~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. 規約
この仕様は、 `INFRA$r に依存する。 ◎ This specification depends on the Infra Standard. [INFRA]
この仕様は、 その内部~algo用に,~JS仕様による`抽象-演算$の概念を利用する。 これは、 それらの返り値を`完了~record$として扱うことに加え, 完了~recordによる包装を外すための[ ~NOABRUPT / ~ABRUPT ]接頭辞の利用を含む。 `ECMASCRIPT$r ◎ This specification uses the abstract operation concept from the JavaScript specification for its internal algorithms. This includes treating their return values as completion records, and the use of ! and ? prefixes for unwrapping those completion records. [ECMASCRIPT]
【概略的には、抽象-演算を~callする所で:】
- ~NOABRUPT が接頭されている場合、 決して`中途完了^にならず,完了~recordの `Value^sl が返される
- ~ABRUPT が接頭されている場合、 `中途完了^に対しては,例外が投出される
- 何も接頭されていない場合、 結果の完了~recordに対する明示的な取扱いを要する
この仕様はまた、 ~JS仕様による`内部~slot$の概念と記法を利用する (内部~slotは、 ~JS~objではなく,~Web~IDLの`~platform~obj$上にあるが。) ◎ This specification also uses the internal slot concept and notation from the JavaScript specification. (Although, the internal slots are on Web IDL platform objects instead of on JavaScript objects.)
注記: これら外来な~JS仕様~規約を~~利用する理由は、 多分に歴史的である。 自前の~web仕様を書く策定者には、 この仕様の例に従うのは避けることが督促される。 ◎ The reasons for the usage of these foreign JavaScript specification conventions are largely historical. We urge you to avoid following our example when writing your own web specifications.
この仕様におけるすべての~numberは、 ([ ~JS `Number$jt / ~Web~IDL `unrestricted double$I 型 ]の様に) 倍精度 64-bit IEEE 754 浮動小数点~値として表現され、 それらに対し遂行されるすべての算術-演算は, そのような値~用の標準な仕方で行うモノトスル。 これは、 特に[ `個別~size付き~queue$secにて述べられる~data構造 ]用に重要になる。 `IEEE-754$r ◎ In this specification, all numbers are represented as double-precision 64-bit IEEE 754 floating point values (like the JavaScript Number type or Web IDL unrestricted double type), and all arithmetic operations performed on them must be done in the standard way for such values. This is particularly important for the data structure described in § 8.1 Queue-with-sizes. [IEEE-754]
4. 可読~stream
4.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【!All data successfully written!】)) .catch(%e => console.error(`何かまずいことが起きたようです^l【!Something went wrong!】, %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 received】, %chunk); }, close() { console.log(`すべての~dataを成功裡に読取りました^l【!All data successfully read!】); }, abort(%e) { console.error(`何かまずいことが起きたようです^l【!Something went wrong!】, %e); } }));
~~自前の `write()$usk 実装から~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【!The stream was already closed】); } else { console.log(%value); } }, %e => console.error(`~streamに~errorが生じたので読取れません^l【!The stream became errored and cannot be read from】, %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を単独の~memory~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" }); let %startingAB = new ArrayBuffer(1024); const %buffer = await readInto(%startingAB); console.log(`最初の 1024 ~byte: ^l【!The first 1024 bytes: 】, %buffer); async function readInto(%buffer) { let %offset = 0; while (%offset < %buffer.byteLength) { const { value: %view, %done } = await %reader.read(new Uint8Array(%buffer, %offset, %buffer.byteLength - %offset)); %buffer = %view.buffer; if (%done) { break; } %offset += %view.byteLength; } return %buffer; }
ここで重要なことは、 ~~最終的な %buffer 値は %startingAB と異なるが、 それら(および すべての中間的~buffer)は,裏では同じ~memoryの割振りを共有することである。 ~bufferは、 毎回 新たな `ArrayBuffer$I ~objに`転送され$る。 %view は、[ 各~propが次のように設定された,新たな `Uint8Array$I ]を読取った結果から~~分割代入( `destructure^en )される ⇒# `buffer^c ~SET 当の `ArrayBuffer$I ~obj, `byteOffset^c ~SET 書込んだ~byte列の~offset, `byteLength^c ~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 view is destructured from the return value of reading 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.
この例は、 ほぼ教育的であることに注意。 実用的な目的においては、 `read()$byob ~method用の `min$brO ~optionが, 正確な~byte数を読取るための もっと容易かつ直接的な仕方を供する: ◎ Note that this example is mostly educational. For practical purposes, the min option of read() provides an easier and more direct way to read an exact number of bytes:
const %reader = readableStream.getReader({ mode: "byob" }); const { value: %view, %done } = await reader.read(new Uint8Array(1024), { min: 1024 }); console.log(`最初の 1024 ~byte: ^l【!The first 1024 bytes: 】, %view);
4.2. `ReadableStream^I ~class
`ReadableStream$I ~classは、 `可読~stream$の一般~概念の具象-~instanceを成す。 それは、 どのような`~chunk$型にも順応-可能であり,[ `下層~source$から給されたが, まだ消費器から読取られていない~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.
4.2.1. ~interface定義
`ReadableStream$I ~class用の~Web~IDL定義は: ◎ The Web IDL definition for the ReadableStream class is given as follows:
[`Exposed$=*, `Transferable$] interface `ReadableStream@I { `ReadableStream$mc(optional `object$ %underlyingSource, optional `QueuingStrategy$I %strategy = {}); static `ReadableStream$I `from$rs(`any$ %asyncIterable); readonly attribute `boolean$ `locked$rs; `Promise$<`undefined$> `cancel$rs(optional `any$ %reason); `ReadableStreamReader$I `getReader$rs(optional `ReadableStreamGetReaderOptions$I %options = {}); `ReadableStream$I `pipeThrough$rs(`ReadableWritablePair$I %transform, optional `StreamPipeOptions$I %options = {}); `Promise$<`undefined$> `pipeTo$rs(`WritableStream$I %destination, optional `StreamPipeOptions$I %options = {}); `sequence$<`ReadableStream$I> `tee$rs(); async iterable<`any$>(optional `ReadableStreamIteratorOptions$I %options = {}); }; typedef (`ReadableStreamDefaultReader$I or `ReadableStreamBYOBReader$I) `ReadableStreamReader@I; enum `ReadableStreamReaderMode@I { `byob@l }; dictionary `ReadableStreamGetReaderOptions@I { `ReadableStreamReaderMode$I `mode@rsgo; }; dictionary `ReadableStreamIteratorOptions@I { `boolean$ `preventCancel@rsio = false; }; dictionary `ReadableWritablePair@I { required `ReadableStream$I `readable@rwp; required `WritableStream$I `writable@rwp; }; dictionary `StreamPipeOptions@I { `boolean$ `preventClose@spo = false; `boolean$ `preventAbort@spo = false; `boolean$ `preventCancel@spo = false; `AbortSignal$I `signal@spo; };
4.2.2. 内部~slot
`ReadableStream$I の各~instanceは、 次に挙げる内部~slotを伴って作成される — 各項に与える記述は`規範的でない^em: ◎ Instances of ReadableStream are created with the internal slots described in the following table: ◎ Internal Slot|Description (non-normative)
- `controller@rS
- ある `ReadableStreamDefaultController$I / ある `ReadableByteStreamController$I ◎ A ReadableStreamDefaultController or ReadableByteStreamController\
- この~streamの状態と~queueを制御する能を伴って作成される。 ◎ created with the ability to control the state and queue of this stream
- `Detached@rS
- 真偽-~flag ◎ A boolean flag\
- この~streamが転送されたとき, ~T に設定される。 ◎ set to true when the stream is transferred
- `disturbed@rS
- 真偽-~flag ◎ A boolean flag\
- 次が生じたとき, ~T に設定される ⇒# この~streamから何かが読取られた/ この~streamが取消された ◎ set to true when the stream has been read from or canceled
- `reader@rS
- `undefined^jv / ある `ReadableStreamDefaultReader$I / ある `ReadableStreamBYOBReader$I ◎ A ReadableStreamDefaultReader or ReadableStreamBYOBReader instance,\
- この~streamを`~lock$している`読取器$は[ 在るならば それ/ 無いならば `undefined^jv ]になる。 ◎ if the stream is locked to a reader, or undefined if it is not
- `state@rS
- 文字列 ◎ A string\
- 内部的に利用される,~streamの現在の状態 — 次に挙げるいずれかになる ⇒# `readable^l, `closed^l, `errored^l ◎ A string containing the stream’s current state, used internally; one of "readable", "closed", or "errored"
- `storedError@rS
- この~streamが どう失敗したかを指示する値 ◎ A value indicating how the stream failed,\
- ~errorした~streamに対し演算するよう試行しているとき, 失敗~事由か例外として与えられることになる。 ◎ to be given as a failure reason or exception when trying to operate on an errored stream
4.2.3. 下層~source~API
`new ReadableStream()$m 構築子は、 1 個目の引数に[ `下層~source$を表現している~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:
dictionary `UnderlyingSource@I { `UnderlyingSourceStartCallback$I `start$usc; `UnderlyingSourcePullCallback$I `pull$usc; `UnderlyingSourceCancelCallback$I `cancel$usc; `ReadableStreamType$I `type$usc; [`EnforceRange$] `unsigned long long$ `autoAllocateChunkSize$usc; }; typedef (`ReadableStreamDefaultController$I or `ReadableByteStreamController$I) `ReadableStreamController@I; callback `UnderlyingSourceStartCallback@I = `any$ (`ReadableStreamController$I %controller); callback `UnderlyingSourcePullCallback@I = `Promise$<`undefined$> (`ReadableStreamController$I %controller); callback `UnderlyingSourceCancelCallback@I = `Promise$<`undefined$> (optional `any$ %reason); enum `ReadableStreamType@I { `bytes$l };
- `start(controller)@usc ( `UnderlyingSourceStartCallback$I 型) ◎ start(controller), of type UnderlyingSourceStartCallback
- この関数は、 `ReadableStream$I を作成する間に即時に~callされる。 ◎ A function that is called immediately during creation of the ReadableStream.
-
これは、 概して,次のために利用される:
- 関連な~event~listenerを設定しておくことにより,`~push~source$を順応させる (その例は、 `下層~push~sourceを伴う可読~stream(背圧~supportなし)$secに見れる)
- `~pull~source$への~accessを獲得する (その例は、 `下層~pull~sourceを伴う可読~stream$secに見れる)
- この設定しておく処理nが非同期的になる場合、 この関数は,成否を通達する~promiseを返すようにすることもできる: 却下される~promiseは、 ~streamを~errorにすることになる。 投出された例外は、 `new ReadableStream()$m 構築子により投出し直されることになる。 ◎ 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)@usc ( `UnderlyingSourcePullCallback$I 型) ◎ pull(controller), of type UnderlyingSourcePullCallback
- この関数は、 ~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~source$に対しては、 この関数は,静止された流れを再開するためにも利用され得る (その例は、 `下層~push~sourceを伴う可読~stream(背圧~supportあり)$secに見れる)。 `~pull~source$に対しては、[ ~streamの中へ~enqueueする新たな`~chunk$を獲得する ]ために利用される (その例は、`下層~pull~sourceを伴う可読~stream$secに見れる)。 ◎ For push sources, this can be used to resume a paused flow, as in § 10.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 § 10.4 A readable stream with an underlying pull source.
- この関数は、 `start()$usc が成功裡に完了するまでは,~callされない。 加えて,繰返し~callされるのは、 それが[ 1 個以上の~chunkを~enqueueするか, ~BYOB要請を充足する ]場合に限られる — 何もしない `pull()$usc 実装は、 断続的に~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~sourceの事例で利用される — そこで返される~promiseは、 新たな~chunkを獲得する処理nを表現する。 例外を投出した場合、 却下される~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)@usc ( `UnderlyingSourceCancelCallback$I 型) ◎ cancel(reason), of type UnderlyingSourceCancelCallback
-
この関数は、
~streamが`消費器$により[
%stream.`cancel()$rs
/%reader.`cancel()$gr
]を介して`取消され$次第,~callされる。 その引数は、 消費器がそれらの~methodに渡したのと同じ値をとる。 ◎ A function that is called whenever the consumer cancels the stream, via stream.cancel() or reader.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~sourceを伴う可読~stream(背圧~supportなし)$secを見よ。 ◎ For all streams, this is generally used to release access to the underlying resource; see for example § 10.1 A readable stream with an underlying push source (no backpressure support).
- この~shutdown処理nが非同期的になる場合、 この関数は,その成否を通達する~promiseを返すようにすることもできる — その結果は、 前述の各種 `cancel()^c ~methodの返り値を介して, その~call元(消費器)へ通信されることになる。 【この関数が】例外を投出することは、 却下される~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. Throwing an exception is treated the same as returning a rejected promise.
-
注記: 取消n処理nが失敗した場合でも、 当の~streamは~closeされ,~errorした状態に置かれることはない — 取消すことで~streamへの関心を失ったことを表出した消費器にとって、 取消n処理nにおける失敗は問われないので。 失敗は、 対応する `cancel()^c ~methodの~call元~のみへ通信される。 ◎ Even if the cancelation process fails, the stream will still close; it will not be put into an errored state. This is because a failure in the cancelation process doesn’t matter to the consumer’s view of the stream, once they’ve expressed disinterest in it by canceling. The failure is only communicated to the immediate caller of the corresponding method.
これは、 `WritableStream$I の`下層~sink$の[ `close$usk / `abort$usk ]~optionの挙動とは異なる — それは、 失敗に際して,対応する `WritableStream$I を~errorした状態に置く。 それらの~optionは、 `生産器$が要請している特定の動作に対応する — そのような動作が失敗した場合、 より持続的な何かの間違いを指示する。 ◎ This is different from the behavior of the close and abort options of a WritableStream's underlying sink, which upon failure put the corresponding WritableStream into an errored state. Those correspond to specific actions the producer is requesting and, if those actions fail, they indicate something more persistently wrong.
- `type@usc (~byte~stream用に限る) ( `ReadableStreamType$I 型) ◎ type (byte streams only), of type ReadableStreamType
- `bytes@l に設定すれば、 構築される `ReadableStream$I は`可読~byte~stream$であることを通達できる。 これは、[ 結果の `ReadableStream$I が — その `getReader()$rs ~methodを介して — `~BYOB読取器$を成功裡に配給-可能にする ]ことを確保する。 また、 下に与える[ `start()$usc / `pull()$usc ]~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~sourceを伴う可読~byte~stream(背圧~supportなし)$secに見れる。 ◎ For an example of how to set up a readable byte stream, including using the different controller interface, see § 10.3 A readable byte stream with an underlying push source (no backpressure support).
- [ `bytes$l / `undefined^jv ]以外の値に設定した場合、 `new ReadableStream()$m 構築子は例外を投出することになる。 ◎ Setting any value other than "bytes" or undefined will cause the ReadableStream() constructor to throw an exception.
- `autoAllocateChunkSize@usc (~byte~stream用に限る) ( `unsigned long long$I 型) ◎ autoAllocateChunkSize (byte streams only), of type unsigned long long
-
正な整数に設定すれば、[
実装が、
下層~sourceの~code用に,書込n用の~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~sourceを伴う可読~byte~stream(背圧~supportなし)$sec, 自動-割振りを伴う`下層~pull~sourceを伴う可読~byte~stream$sec ◎ 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 § 10.3 A readable byte stream with an underlying push source (no backpressure support) without auto-allocation to § 10.5 A readable byte stream with an underlying pull source with auto-allocation.
[ `start()$usc / `pull()$usc ]~methodに渡される %controller 引数の型は, `type$usc ~optionの値に依存し、 それに応じて ⇒# `undefined^jv (または省略された)ならば `ReadableStreamDefaultController$I になる / `bytes$l ならば `ReadableByteStreamController$I になる ◎ 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), then controller will be a ReadableStreamDefaultController. If it’s set to "bytes", then controller will be a ReadableByteStreamController.
4.2.4. 構築子/~method/~prop
- %stream = `new ReadableStream(underlyingSource[, strategy])$m
- 供された`下層~source$を包装している新たな `ReadableStream$I を作成する。 %underlyingSource 引数についての詳細は、 `下層~source~API$secを見よ。 ◎ Creates a new ReadableStream wrapping the provided underlying source. See § 4.2.3 The underlying source API for more details on the underlyingSource argument.
- %strategy 引数は — `~queuing策~API$secにて述べるように — ~streamの`~queuing策$を表現する。 供されなかった場合の既定の挙動は、 `限界水位$ 1 にされた `CountQueuingStrategy$I と同じになる。 ◎ The strategy argument represents the stream’s queuing strategy, as described in § 7.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.
- %stream = `from(asyncIterable)$rs
- 供された[ `iterable@~TC39#sec-iterable-interface$en / `async iterable@~TC39#sec-asynciterable-interface$en ]を包装している新たな `ReadableStream$I を作成する。 ◎ Creates a new ReadableStream wrapping the provided iterable or async iterable.
- これは、 様々な種類の~obj — 次に挙げるものなど — を`可読~stream$の中へ順応するために利用できる ⇒# `array@~TC39#sec-array-objects$en, `async generator@~TC39#sec-asyncgenerator-objects$en, `Node.js readable stream@https://nodejs.org/api/stream.html#class-streamreadable$en ◎ This can be used to adapt various kinds of objects into a readable stream, such as an array, an async generator, or a Node.js readable stream.
- %isLocked = %stream.`locked$rs
- 可読~streamが読取器に`~lockされて$いるかどうかを返す。 ◎ Returns whether or not the readable stream is locked to a reader.
- await %stream.`cancel([ reason ])$rs
- ~streamを`取消して$,[ `消費器$が~streamへの関心を失った ]ことを通達する。 給された %reason 引数は、 `下層~sink$の `cancel()$usc ~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.
- 返される~promiseは、[ ~streamは成功裡に~shut-downされた場合には充足される/ 当の`下層~sink$から そうするときに~errorしたことが通達された場合には却下される ]ことになる。 加えて,当の~streamは現在`~lockされて$いる場合には、 `TypeError$jE で却下されることになる(当の~streamを取消すよう試みることなく)。 ◎ The returned promise will fulfill if the stream shuts down successfully, or reject if the underlying source signaled that there was an error doing so. Additionally, it will reject with a TypeError (without attempting to cancel the stream) if the stream is currently locked.
- %reader = %stream.`getReader()$rs
- `ReadableStreamDefaultReader$I を作成して返すと同時に,~streamを その新たな読取器に`~lock$する。 ~streamが`~lockされて$いる間は、 `解放-$されるまで,他の読取器は~lockを獲得できなくなる。 ◎ Creates a ReadableStreamDefaultReader 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用の読取器を取得することにより,[ 他から[ 読取nが差挟まれたり,~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.
- %reader = %stream.`getReader$rs({ `mode$rsgo: `byob$l })
- `ReadableStreamBYOBReader$I を作成して返すと同時に,~streamを その新たな読取器に`~lock$する。 ◎ Creates a ReadableStreamBYOBReader and locks the stream to the new reader.
- この~callは、 引数をとらない変種と同じ仕方で挙動する — `可読~byte~stream$ (すなわち、[ “開発者が~bufferを給する” 読取りを取扱う能 ]を特定的に備えるように構築された~stream) に限り,働くことを除いて。 返される`~BYOB読取器$は、 その `read()$byob ~methodを介して,[ ~streamから[ 開発者から給された~buffer ]の中へ個々の`~chunk$を直に読取る能 ]を供する — それにより、[ ~bufferの割振りをより精確に制御する ]ことを許容する。 ◎ This call behaves the same way as the no-argument variant, except that it only works on readable byte streams, i.e. streams which were constructed specifically with the ability to handle "bring your own buffer" reading. The returned BYOB reader provides the ability to directly read individual chunks from the stream via its read() method, into developer-supplied buffers, allowing more precise control over allocation.
- %readable = %stream.`pipeThrough$rs({ `writable$rwp, `readable$rwp }[, { `preventClose$spo, `preventAbort$spo, `preventCancel$spo, `signal$spo }])
-
[
`形式変換~stream$(または,他の
{ %writable, %readable }
~pair)を通して,この`可読~stream$を`~pipeする$ ]ための,簡便かつ連鎖-可能な仕方を供する。 それは 単純に、 給された~pairの可書~側へ~streamを~pipeして, 更なる利用~用に可読~側を返す。 ◎ 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 lock it for the duration of the pipe, preventing any other consumer from acquiring a reader.
- await %stream.`pipeTo$rs(%destination[, { `preventClose$spo, `preventAbort$spo, `preventCancel$spo, `signal$spo }])
- この`可読~stream$を, 所与の`可書~stream$ %destination へ`~pipeする$。 [ ~pipeする処理nにおける種々の~error条件 ]の下での挙動は、 渡された~option群により~custom化できる。 この~methodは、 ~promiseを返す — それは、 ~pipeする処理nが ⇒# 成功裡に完了したときは充足される/ 何らかの~errorに遭遇したときは却下される ◎ Pipes this readable stream to a given writable stream destination. 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.
-
~sourceの`可読~stream$ %source, 行先の`可書~stream$ %destination における[ ~error/~closure ]は、 次に従って伝播する: ◎ Errors and closures of the source and destination streams propagate as follows:
- %source における~errorは、 `preventAbort$spo が~truthyでない限り, %destination を`中止する$ことになる。 返される~promiseは、[ %destination を中止する間に~errorが生じたなら その~error / ~ELSE_ %source における~error ]で却下されることになる。 ◎ An error in this source readable stream will abort destination, 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.
- %destination における~errorは、 `preventCancel$spo が~truthyでない限り, %source を`取消す$ことになる。 返される~promiseは、[ %source を取消す間に~errorが生じたなら その~error / ~ELSE_ %dest における~error ]で却下されることになる。 ◎ An error in destination will cancel this 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$spo が~truthyでない限り, %destination も~closeさせることになる。 返される~promiseは、[ %destination を~closeしている間に~errorに遭遇したなら,その~errorで却下される / ~ELSE_ この処理nが完了した時点で充足される ]ことになる。 ◎ When this source readable stream closes, destination will be closed, unless preventClose is truthy. 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.
- %destination が[ ~closeされ始めたとき / ~close中にある ]場合、 `preventCancel$spo が~truthy【!~EQ ~T】でない限り, %source は`取消され$ることになる。 返される~promiseは,[ %source を取消す間に~errorが生じたなら その~error / ~ELSE_ ~streamは~closeされたため~pipeするのに失敗したことを指示する~error ]で却下されることになる。 ◎ If destination starts out closed or closing, this 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.
`signal$spo ~optionに `AbortSignal$I を設定すれば、 対応する `AbortController$I を介して進行中な~pipe演算を中止できるようになる。 この事例では、[ `preventCancel$spo / `preventAbort$spo ]~optionが ~T に設定されない限り,[ %source は`取消され$る/ %destination は`中止-$される ]ことになる。 ◎ The signal option can be set to an AbortSignal to allow aborting an ongoing pipe operation via the corresponding AbortController. In this case, this source readable stream will be canceled, and destination aborted, unless the respective options preventCancel or preventAbort are set.
- [%branch1, %branch2] = %stream.`tee()$rs
- この可読~streamを`二叉化-$して、 結果の 2 個の`分岐$ — いずれも,新たな `ReadableStream$I ~instanceを成す — からなる配列を返す。 ◎ Tees this readable stream, returning a two-element array containing the two resulting branches as new ReadableStream instances.
- ~streamを二叉化すると、 `~lock$され,他の消費器は読取器を獲得できなくなる。 ~streamを`取消す$ためには、 結果の分岐を両者とも取消す — その結果、 この~~複合的な取消n事由が,~streamの`下層~source$まで伝播されることになる。 ◎ 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.
- この~streamは`可読~byte~stream$である場合、 各~分岐は,各`~chunk$に対し自前の複製を受取ることになる。 そうでない場合、 各~分岐~内で見える`~chunk$どうしは同じ~objになるので、 ~chunkが変異-可能な場合, 2 個の分岐~間で互いに干渉し合うことも許容される。 ◎ If this stream is a readable byte stream, then each branch will receive its own copy of each chunk. If not, then 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.
`new ReadableStream(underlyingSource, strategy)@m 構築子~手続きは: ◎ The new ReadableStream(underlyingSource, strategy) constructor steps are:
- ~IF[ %underlyingSource ~EQ ε ] ⇒ %underlyingSource ~SET ~NULL ◎ If underlyingSource is missing, set it to null.
-
%underlyingSourceDict ~LET `~IDL値に変換する$( %underlyingSource, `UnderlyingSource$I ) ◎ Let underlyingSourceDict be underlyingSource, converted to an IDL value of type UnderlyingSource.
注記: %underlyingSource 引数を `UnderlyingSource$I 型として直に宣言できないのは、 元の~objへの参照が失われるからである。 ~obj上の各種`~methodを呼出せる$よう,~objは維持する必要がある。 ◎ We cannot declare the underlyingSource argument as having the UnderlyingSource type directly, because doing so would lose the reference to the original object. We need to retain the object so we can invoke the various methods on it.
- ~NOABRUPT `InitializeReadableStream$A( コレ ) ◎ Perform ! InitializeReadableStream(this).
-
~IF[ %underlyingSourceDict[ "`type$usc" ] ~EQ `bytes$l ]: ◎ If underlyingSourceDict["type"] is "bytes":
- ~IF[ %size ~NEQ `undefined^jv ] ⇒ ~THROW `RangeError$E ◎ If strategy["size"] exists, throw a RangeError exception.
- %highWaterMark ~LET ~ABRUPT `ExtractHighWaterMark$A( %strategy, 0 ) ◎ Let highWaterMark be ? ExtractHighWaterMark(strategy, 0).
- ~ABRUPT `SetUpReadableByteStreamControllerFromUnderlyingSource$A( コレ, %underlyingSource, %underlyingSourceDict, %highWaterMark ) ◎ Perform ? SetUpReadableByteStreamControllerFromUnderlyingSource(this, underlyingSource, underlyingSourceDict, highWaterMark).
-
~ELSE: ◎ Otherwise,
- ~Assert: %underlyingSourceDict[ "`type$usc" ] ~EQ ε ◎ Assert: underlyingSourceDict["type"] does not exist.
- %sizeAlgorithm ~LET ~ABRUPT `ExtractSizeAlgorithm$A( %strategy ) ◎ Let sizeAlgorithm be ! ExtractSizeAlgorithm(strategy).
- %highWaterMark ~LET ~ABRUPT `ExtractHighWaterMark$A( %strategy, 1 ) ◎ Let highWaterMark be ? ExtractHighWaterMark(strategy, 1).
- ~ABRUPT `SetUpReadableStreamDefaultControllerFromUnderlyingSource$A( コレ, %underlyingSource, %underlyingSourceDict, %highWaterMark, %sizeAlgorithm ) ◎ Perform ? SetUpReadableStreamDefaultControllerFromUnderlyingSource(this, underlyingSource, underlyingSourceDict, highWaterMark, sizeAlgorithm).
静的な `from(asyncIterable)@rs ~method手続きは: ◎ The static from(asyncIterable) method steps are:
- ~RET ~ABRUPT `ReadableStreamFromIterable$A( %asyncIterable ) ◎ Return ? ReadableStreamFromIterable(asyncIterable).
`locked@rs 取得子~手続きは: ◎ The locked getter steps are:
- ~RET ~NOABRUPT `IsReadableStreamLocked$A( コレ ) ◎ Return ! IsReadableStreamLocked(this).
`cancel(reason)@rs ~method手続きは: ◎ The cancel(reason) method steps are:
- ~IF[ ~NOABRUPT `IsReadableStreamLocked$A( コレ ) ~EQ ~T ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If ! IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
- ~RET ~NOABRUPT `ReadableStreamCancel$A( コレ, %reason ) ◎ Return ! ReadableStreamCancel(this, reason).
`getReader(options)@rs ~method手続きは: ◎ The getReader(options) method steps are:
- ~IF[ %options[ "`mode$rsgo" ] ~EQ ε ] ⇒ ~RET ~ABRUPT `AcquireReadableStreamDefaultReader$A( コレ ) ◎ If options["mode"] does not exist, return ? AcquireReadableStreamDefaultReader(this).
- ~Assert: %options[ "`mode$rsgo" ] ~EQ `byob$l ◎ Assert: options["mode"] is "byob".
- ~RET ~ABRUPT `AcquireReadableStreamBYOBReader$A( コレ ) ◎ Return ? AcquireReadableStreamBYOBReader(this).
読取器を利用すれば便益を得られるであろう抽象-化の例として、 次のような[ 可読~stream全体を`~chunk$の配列として~memoryの中へ読取るように設計された関数 ]がある: ◎ 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.
`pipeThrough(transform, options)@rs ~method手続きは: ◎ The pipeThrough(transform, options) method steps are:
- ~IF[ ~NOABRUPT `IsReadableStreamLocked$A( コレ ) ~EQ ~T ] ⇒ ~THROW `TypeError$jE ◎ If ! IsReadableStreamLocked(this) is true, throw a TypeError exception.
- ~IF[ ~NOABRUPT `IsWritableStreamLocked$A( %transform[ "`writable$rwp" ] ) ~EQ ~T ] ⇒ ~THROW `TypeError$jE ◎ If ! IsWritableStreamLocked(transform["writable"]) is true, throw a TypeError exception.
- %signal ~LET %options[ "`signal$spo" ] ◎ Let signal be options["signal"]\
- ~IF[ %signal ~EQ ε ] ⇒ %signal ~SET `undefined^jv ◎ if it exists, or undefined otherwise.
- %promise ~LET ~NOABRUPT `ReadableStreamPipeTo$A( コレ, %transform[ "`writable$rwp" ], %options[ "`preventClose$spo" ], %options[ "`preventAbort$spo" ], %options[ "`preventCancel$spo" ], %signal ) ◎ Let promise be ! ReadableStreamPipeTo(this, transform["writable"], options["preventClose"], options["preventAbort"], options["preventCancel"], signal).
- %promise.`PromiseIsHandled^sl ~SET ~T ◎ Set promise.[[PromiseIsHandled]] to true.
- ~RET %transform[ "`readable$rwp" ] ◎ Return transform["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);
`pipeTo(destination, options)@rs ~method手続きは: ◎ The pipeTo(destination, options) method steps are:
- ~IF[ ~NOABRUPT `IsReadableStreamLocked$A( コレ ) ~EQ ~T ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If ! IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
- ~IF[ ~NOABRUPT `IsWritableStreamLocked$A( %destination ) ~EQ ~T ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If ! IsWritableStreamLocked(destination) is true, return a promise rejected with a TypeError exception.
- %signal ~LET %options[ "`signal$spo" ] ◎ Let signal be options["signal"]\
- ~IF[ %signal ~EQ ε ] ⇒ %signal ~SET `undefined^jv ◎ if it exists, or undefined otherwise.
- ~RET ~NOABRUPT `ReadableStreamPipeTo$A( コレ, %destination, %options[ "`preventClose$spo" ], %options[ "`preventAbort$spo" ], %options[ "`preventCancel$spo" ], %signal ) ◎ Return ! ReadableStreamPipeTo(this, destination, options["preventClose"], options["preventAbort"], options["preventCancel"], signal).
`AbortSignal$I を利用すれば、 進行中な`~pipe$RS演算を次のように停止できる: ◎ An ongoing pipe operation can be stopped using an AbortSignal, as follows:
const %controller = new AbortController();
%readable.pipeTo(%writable, { signal: %controller.signal });
/*
… しばらく後で …
◎
... some time later ...
*/
%controller.abort();
(上では `pipeTo()$rs から返される~promise用の~errorの取扱いを省略している。 加えて,[ `preventAbort$spo / `preventCancel$spo ]~optionも、[ ~pipeするのを停止したとき,何が起こるか ]に影響iがあり,考慮するに価する。) ◎ (The above omits error handling for the promise returned by pipeTo(). Additionally, the impact of the preventAbort and preventCancel options what happens when piping is stopped are worth considering.)
上の技法は、 同じ `WritableStream$I の中へ書込んでいる間に, ~pipeされている `ReadableStream$I を切替えるときにも利用できる: ◎ The above technique can be used to switch the ReadableStream being piped, while writing into the same WritableStream:
const %controller = new AbortController(); const %pipePromise = %readable1.pipeTo(%writable, { preventAbort: true, signal: %controller.signal }); /* … しばらく後で … ◎ ... some time later ... */ %controller.abort(); /* 新たな~pipeを開始する前に,当の~pipeが完了するまで待機する: ◎ Wait for the pipe to complete before starting a new one: */ try { await %pipePromise; } catch (%e) { /* 予期される `AbortError^E 例外に限り,ここで吸い取る — 他の失敗は投出し直す。 ◎ Swallow "AbortError" DOMExceptions as expected, but rethrow any unexpected failures. */ if (%e.name !== "AbortError") { throw %e; } } /* 新たな~pipeを開始する。 ◎ Start the new pipe! */ %readable2.pipeTo(%writable);
`tee()@rs ~method手続きは: ◎ The tee() method steps are:
- ~RET ~ABRUPT `ReadableStreamTee$A( コレ, ~F ) ◎ Return ? ReadableStreamTee(this, false).
~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【!Saved the stream to the cache and also uploaded it!】)) .catch(%e => console.error( `~cache時または~upload時に失敗しました: ^l【!Either caching or uploading failed: 】, %e));
4.2.5. 非同期的な反復
- for await (const %chunk of %stream) { ... }
- for await (const %chunk of %stream.values({ `preventCancel$rsio: true })) { ... }
- 当の~streamの`内部~queue$内にある`~chunk$たちを非同期的に反復する。 ◎ Asynchronously iterates over the chunks in the stream’s internal queue.
- 当の~streamを非同期的に反復する間は、 他の消費器が読取器を獲得できないよう, ~streamは`~lock$されることになる。 この~lockは、 非同期c反復子の `return()^c ~methodが~callされたとき, 解放されることになる — 例: `for^c ~loopから `break^c して出ることにより。 ◎ Asynchronously iterating over the stream will lock it, preventing any other consumer from acquiring a reader. The lock will be released if the async iterator’s return() method is called, e.g. by breaking out of the loop.
- 既定では、 非同期c反復子の `return()^c ~methodを~callすると, 当の~streamも`取消す$ことになる。 これを防止するには、 ~streamの `values()^c ~methodを — その `preventCancel$rsio ~optionに ~T を渡して — 利用する。 ◎ By default, calling the async iterator’s return() method will also cancel the stream. To prevent this, use the stream’s values() method, passing true for the preventCancel option.
`ReadableStream$I 用の`非同期~反復子の初期化~手続き$は、 所与の ( %stream, %iterator, %args ) に対し: ◎ The asynchronous iterator initialization steps for a ReadableStream, given stream, iterator, and args, are:
- %reader ~LET ~ABRUPT `AcquireReadableStreamDefaultReader$A( %stream ) ◎ Let reader be ? AcquireReadableStreamDefaultReader(stream).
- %iterator の `非同期c読取器@ ~SET %reader ◎ Set iterator’s reader to reader.
- %preventCancel ~LET %args[0][ "`preventCancel$rsio" ] ◎ Let preventCancel be args[0]["preventCancel"].
- %iterator の `取消-を防止するか@ ~SET %preventCancel ◎ Set iterator’s prevent cancel to preventCancel.
`ReadableStream$I 用の`次回の反復~結果を取得する手続き$は、 所与の ( %stream, %iterator ) に対し: ◎ The get the next iteration result steps for a ReadableStream, given stream and iterator, are:
- %reader ~LET %iterator の`非同期c読取器$ ◎ Let reader be iterator’s reader.
- ~Assert: %reader.`stream$rsR ~NEQ `undefined^jv ◎ Assert: reader.[[stream]] is not undefined.
- %promise ~LET `新たな~promise$ ◎ Let promise be a new promise.
-
%readRequest ~LET 次に挙げる`~item$sctを伴う,新たな`読取n要請$: ◎ Let readRequest be a new read request with the following items:
- `~chunk手続き$rRは、 所与の ( %chunk ) に対し ⇒ `~promiseを解決する$( %promise, %chunk ) ◎ chunk steps, given chunk • Resolve promise with chunk.
-
`~close手続き$rRは: ◎ close steps
- ~NOABRUPT `ReadableStreamDefaultReaderRelease$A( %reader ) ◎ Perform ! ReadableStreamDefaultReaderRelease(reader).
- `~promiseを解決する$( %promise, `反復~終了$i ) ◎ Resolve promise with end of iteration.
-
`~error手続き$rRは、 所与の ( %e ) に対し: ◎ error steps, given e
- ~NOABRUPT `ReadableStreamDefaultReaderRelease$A( %reader ) ◎ Perform ! ReadableStreamDefaultReaderRelease(reader).
- `~promiseを却下する$( %promise, %e ) ◎ Reject promise with e.
- ~NOABRUPT `ReadableStreamDefaultReaderRead$A( コレ, %readRequest ) ◎ Perform ! ReadableStreamDefaultReaderRead(this, readRequest).
- ~RET %promise ◎ Return promise.
`ReadableStream$I 用の`非同期~反復子の~return手続き$は、 所与の ( %stream, %iterator, %arg ) に対し: ◎ The asynchronous iterator return steps for a ReadableStream, given stream, iterator, and arg, are:
- %reader ~LET %iterator の`非同期c読取器$ ◎ Let reader be iterator’s reader.
- ~Assert: %reader.`stream$rsR ~NEQ `undefined^jv ◎ Assert: reader.[[stream]] is not undefined.
- ~Assert: %reader.`readRequests$rsR は`空$である — `next()^c に対する以前の~callは、 非同期c反復子の機構により, これが~callされる前に決着することが保証されるので。 ◎ Assert: reader.[[readRequests]] is empty, as the async iterator machinery guarantees that any previous calls to next() have settled before this is called.
-
~IF[ %iterator の`取消-を防止するか$ ~EQ ~F ]: ◎ If iterator’s prevent cancel is false:
- %result ~LET ~NOABRUPT `ReadableStreamReaderGenericCancel$A( %reader, %arg ) ◎ Let result be ! ReadableStreamReaderGenericCancel(reader, arg).
- ~NOABRUPT `ReadableStreamDefaultReaderRelease$A( %reader ) ◎ Perform ! ReadableStreamDefaultReaderRelease(reader).
- ~RET %result ◎ Return result.
- ~NOABRUPT `ReadableStreamDefaultReaderRelease$A( %reader ) ◎ Perform ! ReadableStreamDefaultReaderRelease(reader).
- ~RET `解決される~promise$( `undefined^jv ) ◎ Return a promise resolved with undefined.
4.2.6. `postMessage()^m を介する転送
%destination.postMessage(%rs, { transfer: [%rs] });
- `ReadableStream$I を別の[ ~frame/~window/~worker ]へ送信する。 ◎ Sends a ReadableStream to another frame, window, or worker.
- 転送された~streamは、 元の~streamとまったく同じに利用できる。 以降、 元の~streamは`~lock$され,利用-不能になる。 ◎ The transferred stream can be used exactly like the original. The original will become locked and no longer directly usable.
`ReadableStream$I ~objは、 `転送-可能$である: ◎ ReadableStream objects are transferable objects.\
-
その`転送-手続き$は、 所与の ( %値, %~data保持体 ) に対し: ◎ Their transfer steps, given value and dataHolder, are:
- ~IF[ ! `IsReadableStreamLocked$A( %値 ) ~EQ ~T ] ⇒ ~THROW `DataCloneError$E ◎ If ! IsReadableStreamLocked(value) is true, throw a "DataCloneError" DOMException.
- %port1 ~LET `現在の~realm$内の`新たな$ `MessagePort$I ◎ Let port1 be a new MessagePort in the current Realm.
- %port2 ~LET `現在の~realm$内の`新たな$ `MessagePort$I ◎ Let port2 be a new MessagePort in the current Realm.
- `~portを連絡する$( %port1, %port2 ) ◎ Entangle port1 and port2.
- %writable ~LET `現在の~realm$内の`新たな$ `WritableStream$I ◎ Let writable be a new WritableStream in the current Realm.
- ~NOABRUPT `SetUpCrossRealmTransformWritable$A( %writable, %port1 ) ◎ Perform ! SetUpCrossRealmTransformWritable(writable, port1).
- %promise ~LET ~NOABRUPT `ReadableStreamPipeTo$A( %値, %writable, ~F, ~F, ~F ) ◎ Let promise be ! ReadableStreamPipeTo(value, writable, false, false, false).
- %promise.`PromiseIsHandled^sl ~SET ~T ◎ Set promise.[[PromiseIsHandled]] to true.
- %~data保持体.`port^sl ~SET ~NOABRUPT `StructuredSerializeWithTransfer$A( %port2, « %port2 » ) ◎ Set dataHolder.[[port]] to ! StructuredSerializeWithTransfer(port2, « port2 »).
-
その`転送-受信-時の手続き$は、 所与の ( %~data保持体, %値 ) に対し: ◎ Their transfer-receiving steps, given dataHolder and value, are:
- %deserializedRecord ~LET ~NOABRUPT `StructuredDeserializeWithTransfer$A( %~data保持体.`port^sl, `現在の~realm$ ) ◎ Let deserializedRecord be ! StructuredDeserializeWithTransfer(dataHolder.[[port]], the current Realm).
- %port ~LET %deserializedRecord.`Deserialized^sl ◎ Let port be deserializedRecord.[[Deserialized]].
- ~NOABRUPT `SetUpCrossRealmTransformReadable$A( %値, %port ) ◎ Perform ! SetUpCrossRealmTransformReadable(value, port).
4.3. `ReadableStreamGenericReader^I ~mixin
`ReadableStreamGenericReader$I ~mixinは、[ `ReadableStreamDefaultReader$I, `ReadableStreamBYOBReader$I ]~objから共有される共通な[ 内部~slot/取得子/~method ]を定義する。 ◎ The ReadableStreamGenericReader mixin defines common internal slots, getters and methods that are shared between ReadableStreamDefaultReader and ReadableStreamBYOBReader objects.
4.3.1. ~mixin定義
`ReadableStreamGenericReader$I ~mixin用の~Web~IDL定義は: ◎ The Web IDL definition for the ReadableStreamGenericReader mixin is given as follows:
interface mixin `ReadableStreamGenericReader@I { readonly attribute `Promise$<`undefined$> `closed$gr; `Promise$<`undefined$> `cancel$gr(optional `any$ %reason); };
4.3.2. 内部~slot
`ReadableStreamGenericReader$I ~mixinを`内包-$している~classの各~instanceは、 次に挙げる内部~slotを伴って作成される — 各項に与える記述は`規範的でない^em: ◎ Instances of classes including the ReadableStreamGenericReader mixin are created with the internal slots described in the following table: ◎ Internal Slot|Description (non-normative)
- `closedPromise@rsR
- この読取器の `closed$gr 取得子から返される~promise。 ◎ A promise returned by the reader’s closed getter
- `stream@rsR
- この読取器を所有する `ReadableStream$I ~instance。 ◎ A ReadableStream instance that owns this reader
4.3.3. ~methodと~prop
`closed@gr 取得子~手続きは: ◎ The closed getter steps are:
- ~RET コレ.`closedPromise$rsR ◎ Return this.[[closedPromise]].
`cancel(reason)@gr ~method手続きは: ◎ The cancel(reason) method steps are:
- ~IF[ コレ.`stream$rsR ~EQ `undefined^jv ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.
- ~RET ~NOABRUPT `ReadableStreamReaderGenericCancel$A( コレ, %reason ) ◎ Return ! ReadableStreamReaderGenericCancel(this, reason).
4.4. `ReadableStreamDefaultReader^I ~class
`ReadableStreamDefaultReader$I ~classは、[ `ReadableStream$I ~instanceから配給されるように設計された `既定の読取器$ ]を表現する。 ◎ The ReadableStreamDefaultReader class represents a default reader designed to be vended by a ReadableStream instance.
4.4.1. ~interface定義
`ReadableStreamDefaultReader$I ~class用の~Web~IDL定義は: ◎ The Web IDL definition for the ReadableStreamDefaultReader class is given as follows:
[`Exposed$=*] interface `ReadableStreamDefaultReader@I { `ReadableStreamDefaultReader$mc(`ReadableStream$I %stream); `Promise$<`ReadableStreamReadResult$I> `read$dr(); `undefined$ `releaseLock$dr(); }; `ReadableStreamDefaultReader$I includes `ReadableStreamGenericReader$I; dictionary `ReadableStreamReadResult@I { `any$ `value@rrr; `boolean$ `done@rrr; };
4.4.2. 内部~slot
`ReadableStreamDefaultReader$I の各~instanceは、 `ReadableStreamGenericReader$I 用に定義された内部~slotに加え, 次に挙げる内部~slotも伴って作成される — 各項に与える記述は`規範的でない^em: ◎ Instances of ReadableStreamDefaultReader are created with the internal slots defined by ReadableStreamGenericReader, and those described in the following table: ◎ Internal Slot|Description (non-normative)
- `readRequests@rsR
- `読取n要請$たちが成す`~list$ ◎ A list of read requests,\
- `消費器$が[ 可用になるより早く`~chunk$たちを要請する ]とき,利用される。 ◎ used when a consumer requests chunks sooner than they are available
`読取n要請@ は、 次に挙げる`~item$sctからなる`構造体$である — これらの~itemは、[ `可読~stream$の[ `内部~queue$が埋められた/状態が変化した ]ときに対する反応 ]として遂行される~algoを与える: ◎ A read request is a struct containing three algorithms to perform in reaction to filling the readable stream's internal queue or changing its state. It has the following items:
- `~chunk手続き@rR ◎ chunk steps
- 1 個の`~chunk$をとる~algo ◎ An algorithm taking a chunk,\
- ~chunkが読取り用に可用になったとき~callされる。 ◎ called when a chunk is available for reading
- `~close手続き@rR ◎ close steps
- 引数をとらない~algo ◎ An algorithm taking no arguments,\
- ~streamは~closeされたため,可用な`~chunk$は無いとき~callされる。 ◎ called when no chunks are available because the stream is closed
- `~error手続き@rR ◎ error steps
- ~JS値をとる~algo ◎ An algorithm taking a JavaScript value,\
- ~streamは~errorしたため,可用な`~chunk$は無いとき~callされる。 ◎ called when no chunks are available because the stream is errored
4.4.3. 構築子/~method/~prop
- %reader = `new ReadableStreamDefaultReader(stream)$m
-
これは、
%stream.`getReader()$rs
を~callすることと等価になる。 ◎ This is equivalent to calling stream.getReader(). - await %reader.`closed$gr
- ~promiseを返す — それは、 ~streamが~closeされたときは 充足され,[ ~streamがどこかで~errorしたとき / ~streamが~closeし終える前に読取器の~lockが`解放-$されたとき ]は 却下されることになる。 ◎ 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.
- await %reader.`cancel([ reason ])$gr
-
当の読取器は`作動中$である場合、
%stream.`cancel(reason)$rs
と同じに挙動する。 ◎ If the reader is active, behaves the same as stream.cancel(reason). - { %value, %done } = await %reader.`read()$dr
-
~promiseを返す — この~promiseは: ◎ Returns a promise that\
- ~streamの内部~queueからの次回の可用な`~chunk$に~accessすることを許容する。 ◎ 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が空になったときは、 `下層~source$から更に~dataが~pullされることになる。 ◎ If reading a chunk causes the queue to become empty, more data will be pulled from the underlying source.
- %reader.`releaseLock()$dr
- 対応する~stream上の読取器の`~lockを解放-$する。 解放されたなら、 読取器は`作動中$でなくなる。 ~lockが解放された時点から、 読取器は,[ 結付けられた~streamが~errorした場合は~errorしたように/ 他の場合は~closeされたように ]現れるようになる。 ◎ 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.
- まだ処理待ちにある読取n要請がある間に, 読取器の~lockが解放された場合、 読取器の `read()$dr ~methodから返された~promiseは, 即時に `TypeError$jE で却下される。 読取られなかった~chunkは、 ~streamの`内部~queue$内に残され, 後で新たな読取器を獲得することにより読取れる。 ◎ If the reader’s lock is released while it still has pending read requests, then the promises returned by the reader’s read() method are immediately rejected with a TypeError. Any unread chunks remain in the stream’s internal queue and can be read later by acquiring a new reader.
`new ReadableStreamDefaultReader(stream)@m 構築子~手続きは: ◎ The new ReadableStreamDefaultReader(stream) constructor steps are:
- ~ABRUPT `SetUpReadableStreamDefaultReader$A(コレ, %stream). ◎ Perform ? SetUpReadableStreamDefaultReader(this, stream).
`read()@dr ~method手続きは: ◎ The read() method steps are:
- ~IF[ コレ.`stream$rsR ~EQ `undefined^jv ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.
- %promise ~LET `新たな~promise$ ◎ Let promise be a new promise.
-
%readRequest ~LET 次に挙げる`~item$sctを伴う,新たな`読取n要請$ : ◎ Let readRequest be a new read request with the following items:
- `~chunk手続き$rRは、 所与の ( %chunk ) に対し ⇒ `~promiseを解決する$( %promise, «[ "`value$rrr" → %chunk, "`done$rrr" → ~F ]» ) ◎ chunk steps, given chunk • Resolve promise with «[ "value" → chunk, "done" → false ]».
- `~close手続き$rRは ⇒ `~promiseを解決する$( %promise, «[ "`value$rrr" → `undefined^jv, "`done$rrr" → ~T ]» ) ◎ close steps • Resolve promise with «[ "value" → undefined, "done" → true ]».
- `~error手続き$rRは、 所与の ( %e ) に対し ⇒ `~promiseを却下する$( %promise, %e ) ◎ error steps, given e • Reject promise with e.
- ~RET ~NOABRUPT `ReadableStreamDefaultReaderRead$A( コレ, %readRequest ) ◎ Perform ! ReadableStreamDefaultReaderRead(this, readRequest).
- ~RET %promise ◎ Return promise.
`releaseLock()@dr ~method手続きは: ◎ The releaseLock() method steps are:
- ~IF[ コレ.`stream$rsR ~EQ `undefined^jv ] ⇒ ~RET ◎ If this.[[stream]] is undefined, return.
- ~NOABRUPT `ReadableStreamDefaultReaderRelease$A( コレ ) ◎ Perform ! ReadableStreamDefaultReaderRelease(this).
4.5. `ReadableStreamBYOBReader^I ~class
`ReadableStreamBYOBReader$I ~classは、[ `ReadableStream$I ~instanceにより配給されるように設計された `~BYOB読取器$ ]を表現する。 ◎ The ReadableStreamBYOBReader class represents a BYOB reader designed to be vended by a ReadableStream instance.
4.5.1. ~interface定義
`ReadableStreamBYOBReader$I ~class用の~Web~IDL定義は: ◎ The Web IDL definition for the ReadableStreamBYOBReader class is given as follows:
[`Exposed$=*] interface `ReadableStreamBYOBReader@I { `ReadableStreamBYOBReader$mc(`ReadableStream$I %stream); `Promise$<`ReadableStreamReadResult$I> `read$byob(`ArrayBufferView$I %view, optional `ReadableStreamBYOBReaderReadOptions$I %options = {}); `undefined$ `releaseLock$byob(); }; `ReadableStreamBYOBReader$I includes `ReadableStreamGenericReader$I; dictionary `ReadableStreamBYOBReaderReadOptions@I { [`EnforceRange$] `unsigned long long$ `min@brO = 1; };
4.5.2. 内部~slot
`ReadableStreamBYOBReader$I の各~instanceは、 `ReadableStreamGenericReader$I 用に定義された内部~slotに加え, 次に挙げる内部~slotも伴って作成される — 各項に与える記述は`規範的でない^em: ◎ Instances of ReadableStreamBYOBReader are created with the internal slots defined by ReadableStreamGenericReader, and those described in the following table: ◎ Internal Slot|Description (non-normative)
- `readIntoRequests@rsR
- `中へ読取る要請$たちが成す`~list$ ◎ A list of read-into requests,\
- `消費器$が[ 可用になるより早く`~chunk$たちを要請する ]とき,利用される。 ◎ used when a consumer requests chunks sooner than they are available
`中へ読取る要請@ は、 次に挙げる`~item$sctからなる`構造体$である — これらの~itemは、[ `可読~byte~stream$の[ `内部~queue$が埋められた/状態が変化した ]ときに対する反応 ]として遂行される~algoを与える: ◎ A read-into request is a struct containing three algorithms to perform in reaction to filling the readable byte stream's internal queue or changing its state. It has the following items:
- `~chunk手続き@riR ◎ chunk steps
- `~chunk$をとる~algo ◎ An algorithm taking a chunk,\
- ~chunkが読取り用に可用になったとき~callされる。 ◎ called when a chunk is available for reading
- `~close手続き@riR ◎ close steps
- [ 1 個の`~chunk$/ `undefined^jv ]をとる~algo ◎ An algorithm taking a chunk or undefined,\
- ~streamは~closeされたため,可用な`~chunk$は無いとき~callされる。 ◎ called when no chunks are available because the stream is closed
- `~error手続き@riR ◎ error steps
- ~JS値をとる~algo ◎ An algorithm taking a JavaScript value,\
- ~streamは~errorしたため可用な`~chunk$は無いとき~callされる。 ◎ called when no chunks are available because the stream is errored
注記:
`~close手続き$riRが`~chunk$をとるのは、
アリなら,~call元に裏~memoryを返せるようにするためである。
例えば
%byobReader.`read(chunk)$byob
は、
~closeされた~streamに対しては
{ value: %newViewOnSameMemory, done: true }
で充足されることになる。
当の~streamが`取消され$た場合、
裏~memoryは破棄され,代わりに より伝統的な
{ value: undefined, done: true }
で充足される。
◎
The close steps take a chunk so that it can return the backing memory to the caller if possible. For example, byobReader.read(chunk) will fulfill with { value: newViewOnSameMemory, done: true } for closed streams. If the stream is canceled, the backing memory is discarded and byobReader.read(chunk) fulfills with the more traditional { value: undefined, done: true } instead.
4.5.3. 構築子/~method/~prop
- %reader = `new ReadableStreamBYOBReader(stream)$m
-
これは、
%stream.`getReader$rs({ `mode$rsgo: `byob$l })
を~callすることと等価になる。 ◎ This is equivalent to calling stream.getReader({ mode: "byob" }). - await %reader.`closed$gr
- ~promiseを返す — それは、 ~streamが~closeされたときは 充足され,[ ~streamがどこかで~errorしたとき / ~streamが~closeし終える前に読取器の~lockが`解放-$されたとき ]は 却下されることになる。 ◎ 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.
- await %reader.`cancel([ reason ])$gr
-
当の読取器は`作動中$である場合、
%stream.`cancel(reason)$rs
と同じに挙動する。 ◎ If the reader is active, behaves the same stream.cancel(reason). - { %value, %done } = await %reader.`read(view, options)$byob
-
~byte列を %view の中へ読取るよう試みて、 その結果で解決される~promiseを返す: ◎ Attempts to read bytes into view, and returns a promise resolved with the result:
-
可用な~chunkが無くなったときは、
{ value: %newView, done: false }
の形による~objで充足されることになる。 この事例では、 %view は`切離され@~WEBIDLjs#dfn-detach$るので,もはや利用-可能でなくなるが、 %newView は同じ裏~memory領域への新たな(かつ同じ型の)~viewになり, ~chunkの~dataは その中へ書込まれるようになる。 ◎ If the chunk does become available, the promise will be fulfilled with an object of the form { value: newView, done: false }. In this case, view will be detached and no longer usable, but newView will be a new view (of the same type) onto the same backing memory region, with the chunk’s data written into it. -
~streamが~closeされたときは、
{ value: %newView, done: true }
の形による~objで充足されることになる。 この事例では %view は`切離され@~WEBIDLjs#dfn-detach$,もはや利用-可能でなくなるが、 %newView は同じ裏~memory領域への新たな(かつ同じ型の)~viewになる — その~memoryが~call元に返されることを確保するため,改変を加えずに。 ◎ If the stream becomes closed, the promise will be fulfilled with an object of the form { value: newView, done: true }. In this case, view will be detached and no longer usable, but newView will be a new view (of the same type) onto the same backing memory region, with no modifications, to ensure the memory is returned to the caller. -
%reader が`取消され$た場合、
~promiseは
{ value: undefined, done: true }
の形による~objで充足されることになる。 この事例では、 %view の裏~memory領域は破棄され,~call元には返されない。 ◎ If the reader is canceled, the promise will be fulfilled with an object of the form { value: undefined, done: true }. In this case, the backing memory region of view is discarded and not returned to the caller. - ~streamが~errorしたときは、 関連な~errorで却下されることになる。 ◎ If the stream becomes errored, the promise will be rejected with the relevant error.
~chunkの読取りにより~queueが空になったときは、 `下層~source$から更に~dataが~pullされることになる。 ◎ If reading a chunk causes the queue to become empty, more data will be pulled from the underlying source.
-
可用な~chunkが無くなったときは、
- %options の `min$brO が与えられた場合、 当の~promiseは,[ 所与の最小~個数の要素が可用になるか,~streamが~closeされた場合 ]に限り充足されることになる — ~closeされた場合、 ~promiseは当の~stream内の残りの要素たちで充足され,その個数は初期~時に要請された量より少ないかもしれない。 ここでの “個数” は、[ (有型~配列~用には)%newView の `length^c / ( `DataView$I 用には) %newView の `byteLength^c ]で与えられる。 `min$brO が与えられなかった場合、 当の~promiseは 1 個以上の要素が可用になったとき解決される。 ◎ If min is given, then the promise will only be fulfilled as soon as the given minimum number of elements are available. Here, the "number of elements" is given by newView’s length (for typed arrays) or newView’s byteLength (for DataViews). If the stream becomes closed, then the promise is fulfilled with the remaining elements in the stream, which might be fewer than the initially requested amount. If not given, then the promise resolves when at least one element is available.
- %reader.`releaseLock()$byob
- 対応する~stream上の読取器の`~lockを解放-$する。 解放されたなら、 読取器は`作動中$でなくなる。 ~lockが解放された時点から、 読取器は,[ 結付けられた~streamが~errorした場合は~errorしたように/ 他の場合は~closeされたように ]現れるようになる。 ◎ 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.
- まだ処理待ちにある読取n要請がある間に, 読取器の~lockが解放された場合、 読取器の `read()$byob ~methodから返された~promiseは, 即時に `TypeError$jE で却下される。 読取られなかった~chunkは、 ~streamの`内部~queue$内に残され, 後で新たな読取器を獲得することにより読取れる。 ◎ If the reader’s lock is released while it still has pending read requests, then the promises returned by the reader’s read() method are immediately rejected with a TypeError. Any unread chunks remain in the stream’s internal queue and can be read later by acquiring a new reader.
`new ReadableStreamBYOBReader(stream)@m 構築子~手続きは: ◎ The new ReadableStreamBYOBReader(stream) constructor steps are:
- ~ABRUPT `SetUpReadableStreamBYOBReader$A(コレ, %stream). ◎ Perform ? SetUpReadableStreamBYOBReader(this, stream).
`read(view, options)@byob ~method手続きは: ◎ The read(view, options) method steps are:
- ~IF[ %view.`ByteLength^sl ~EQ 0 ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If view.[[ByteLength]] is 0, return a promise rejected with a TypeError exception.
- ~IF[ %view.`ViewedArrayBuffer^sl.`ArrayBufferByteLength^sl ~EQ 0 ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If view.[[ViewedArrayBuffer]].[[ArrayBufferByteLength]] is 0, return a promise rejected with a TypeError exception.
- ~IF[ ~NOABRUPT `IsDetachedBuffer$Ax( %view.`ViewedArrayBuffer^sl)~EQ ~T ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If ! IsDetachedBuffer(view.[[ViewedArrayBuffer]]) is true, return a promise rejected with a TypeError exception.
- %min ~LET %options[ "`min$brO" ] ◎ ↓
- ~IF[ %min ~EQ 0 ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If options["min"] is 0, return a promise rejected with a TypeError exception.
- ~IF[ %view は `TypedArrayName^sl 内部~slotを有する ] ⇒ ~IF[ %min ~GT %view.`ArrayLength^sl ] ⇒ ~RET `却下される~promise$( `RangeError$E 例外 ) ◎ If view has a [[TypedArrayName]] internal slot, • If options["min"] > view.[[ArrayLength]], return a promise rejected with a RangeError exception.
- ~ELSE(すなわち, %view は `DataView$I である) ⇒ ~IF[ %min ~GT %view.`ByteLength^sl ] ⇒ ~RET `却下される~promise$( `RangeError$E 例外 ) ◎ Otherwise (i.e., it is a DataView), • If options["min"] > view.[[ByteLength]], return a promise rejected with a RangeError exception.
- ~IF[ コレ.`stream$rsR ~EQ `undefined^jv ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.
- %promise ~LET `新たな~promise$ ◎ Let promise be a new promise.
-
%readIntoRequest ~LET 次に挙げる`~item$sctを伴う,新たな`中へ読取る要請$: ◎ Let readIntoRequest be a new read-into request with the following items:
- `~chunk手続き$riRは、 所与の ( %chunk ) に対し ⇒ `~promiseを解決する$( %promise, «[ "`value$rrr" → %chunk, "`done$rrr" → ~F ]» ) ◎ chunk steps, given chunk • Resolve promise with «[ "value" → chunk, "done" → false ]».
- `~close手続き$riRは、 所与の ( %chunk ) に対し ⇒ `~promiseを解決する$( %promise, «[ "`value$rrr" → %chunk, "`done$rrr" → ~T ]» ) ◎ close steps, given chunk • Resolve promise with «[ "value" → chunk, "done" → true ]».
- `~error手続き$riRは、 所与の ( %e ) に対し ⇒ `~promiseを却下する$( %promise, %e ) ◎ error steps, given e • Reject promise with e.
- ~RET ~NOABRUPT `ReadableStreamBYOBReaderRead$A( コレ, %view, %min, %readIntoRequest ) ◎ Perform ! ReadableStreamBYOBReaderRead(this, view, options["min"], readIntoRequest).
- ~RET %promise ◎ Return promise.
`releaseLock()@byob ~method手続きは: ◎ The releaseLock() method steps are:
- ~IF[ コレ.`stream$rsR ~EQ `undefined^jv ] ⇒ ~RET ◎ If this.[[stream]] is undefined, return.
- ~NOABRUPT `ReadableStreamBYOBReaderRelease$A( コレ ) ◎ Perform ! ReadableStreamBYOBReaderRelease(this).
4.6. `ReadableStreamDefaultController^I ~class
`ReadableStreamDefaultController$I ~classは、 `ReadableStream$I の状態と`内部~queue$の制御を許容する~methodたちを有する。 `可読~byte~stream$でない `ReadableStream$I を構築するときは、 `下層~source$には,操作するための 対応する `ReadableStreamDefaultController$I ~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.
4.6.1. ~interface定義
`ReadableStreamDefaultController$I ~class用の~Web~IDL定義は: ◎ The Web IDL definition for the ReadableStreamDefaultController class is given as follows:
[`Exposed$=*] interface `ReadableStreamDefaultController@I { readonly attribute `unrestricted double$? `desiredSize$rsdc; `undefined$ `close$rsdc(); `undefined$ `enqueue$rsdc(optional `any$ %chunk); `undefined$ `error$rsdc(optional `any$ %e); };
4.6.2. 内部~slot
`ReadableStreamDefaultController$I の各~instanceは、 次に挙げる内部~slotを伴って作成される — 各項に与える記述は`規範的でない^em: ◎ Instances of ReadableStreamDefaultController are created with the internal slots described in the following table: ◎ Internal Slot|Description (non-normative)
- `cancelAlgorithm@rsdC
- 1 個の引数(取消~事由)をとり,~promiseを返す~algo ◎ A promise-returning algorithm, taking one argument (the cancel reason),\
- 要請された取消を`下層~source$へ通信する。 ◎ which communicates a requested cancelation to the underlying source
- `closeRequested@rsdC
- 真偽-~flag ◎ A boolean flag\
- 次に該当するかどうかを指示する ⇒ 当の~streamは その`下層~source$により~closeされたが, その内部~queueには読取られていない`~chunk$がまだある。 ◎ 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
- `pullAgain@rsdC
- 真偽-~flag ◎ A boolean flag\
- 次の間, ~T に設定される ⇒ 更に~dataを~pullするために,~streamの仕組みにて`下層~source$の~pull~algoが要請されたが、 以前の~callがまだ実行-中にあるため,まだ~pullを行えない。 ◎ 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@rsdC
- ~promiseを返す~algo ◎ A promise-returning algorithm\
- `下層~source$から~dataを~pullする。 ◎ that pulls data from the underlying source
- `pulling@rsdC
- 真偽-~flag ◎ A boolean flag\
- 次の間, ~T に設定される ⇒ `下層~source$の~pull~algoは実行-中にあるが,それが返した~promiseはまだ充足されていない。 ◎ set to true while the underlying source's pull algorithm is executing and the returned promise has not yet fulfilled,\
- これは、 再入~callを防止するために利用される。 ◎ used to prevent reentrant calls
- `queue@rsdC
- 当の~streamの[ `~chunk$たちが成す内部~queue ]を表現する`~list$ ◎ A list representing the stream’s internal queue of chunks
- `queueTotalSize@rsdC
- `queue$rsdC 内に格納されている すべての~chunkの合計~size (`個別~size付き~queue$secを見よ) ◎ The total size of all the chunks stored in [[queue]] (see § 8.1 Queue-with-sizes)
- `started@rsdC
- 真偽-~flag ◎ A boolean flag\
- 当の~streamの`下層~source$が開始処理【 `start()$usc 】を完遂したかどうかを指示する。 ◎ indicating whether the underlying source has finished starting
- `strategyHWM@rsdC
- ~number ◎ A number\
- 当の~streamの`~queuing策$の一部として,構築子に給されたもの。 その`下層~source$には、 この~numberを境に`背圧$が適用されるようになる。 【 HWM = `High-Water Mark^en (`限界水位$) 】 ◎ 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@rsdC
- ある~algo ◎ An algorithm\
- 当の~streamの`~queuing策$の一部として給され, ~enqueueされた`~chunk$たちの~sizeを計算する。 ◎ to calculate the size of enqueued chunks, as part of the stream’s queuing strategy
- `stream@rsdC
- ある `ReadableStream$I ◎ ↓
- この制御器により制御される`可読~stream$。 ◎ The ReadableStream instance controlled
4.6.3. ~method/~prop
- %desiredSize = %controller.`desiredSize$rsdc
- 制御先の`~streamの内部~queueの残り~size$を返す。 それは、 負にもなり得る — ~queueを溢れた場合に。 `下層~source$が`背圧$をいつどのように適用するかを決定するときは、 この情報が利用されるべきである。 ◎ 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.
- %controller.`close()$rsdc
- 制御先の可読~streamを~closeする。 `消費器$は依然として,それまでに~enqueueされた`~chunk$たちを~streamから読取れるが、 それらが読取られたなら,~streamは~closeされる。 ◎ Closes 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.
- %controller.`enqueue(chunk)$rsdc
- 所与の`~chunk$ %chunk を制御先の可読~stream内に~enqueueする。 ◎ Enqueues the given chunk chunk in the controlled readable stream.
- %controller.`error(e)$rsdc
- 制御先の可読~streamを~errorにする — 以降のヤリトリは、 すべて所与の~error %e で失敗させる。 ◎ Errors the controlled readable stream, making all future interactions with it fail with the given error e.
`desiredSize@rsdc 取得子~手続きは: ◎ The desiredSize getter steps are:
- ~RET ~NOABRUPT `ReadableStreamDefaultControllerGetDesiredSize$A( コレ ) ◎ Return ! ReadableStreamDefaultControllerGetDesiredSize(this).
`close()@rsdc ~method手続きは: ◎ The close() method steps are:
- ~IF[ ~NOABRUPT `ReadableStreamDefaultControllerCanCloseOrEnqueue$A( コレ ) ~EQ ~F ] ⇒ ~THROW `TypeError$jE ◎ If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(this) is false, throw a TypeError exception.
- ~NOABRUPT `ReadableStreamDefaultControllerClose$A( コレ ) ◎ Perform ! ReadableStreamDefaultControllerClose(this).
`enqueue(chunk)@rsdc ~method手続きは: ◎ The enqueue(chunk) method steps are:
- ~IF[ ~NOABRUPT `ReadableStreamDefaultControllerCanCloseOrEnqueue$A( コレ ) ~EQ ~F ] ⇒ ~THROW `TypeError$jE ◎ If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(this) is false, throw a TypeError exception.
- ~ABRUPT `ReadableStreamDefaultControllerEnqueue$A( コレ, %chunk ) ◎ Perform ? ReadableStreamDefaultControllerEnqueue(this, chunk).
`error(e)@rsdc ~method手続きは: ◎ The error(e) method steps are:
- ~NOABRUPT `ReadableStreamDefaultControllerError$A( コレ, %e ) ◎ Perform ! ReadableStreamDefaultControllerError(this, e).
4.6.4. 内部~method
各 `ReadableStreamDefaultController$I ~instanceは、 以下に与える内部~methodを実装する。 可読~streamの実装は、 `制御器との~interface法$secにて論じるように,[ それら, または ~BYOB制御器~用の それらに相当するもの ]いずれかを多形態的に~callすることになる。 ◎ The following are internal methods implemented by each ReadableStreamDefaultController instance. The readable stream implementation will polymorphically call to either these, or to their counterparts for BYOB controllers, as discussed in § 4.9.2 Interfacing with controllers.
`[[CancelSteps]]( reason )@rsdc は、 `CancelSteps$sl の契約を実装する。 それは、次の手続きを遂行する: ◎ [[CancelSteps]](reason) implements the [[CancelSteps]] contract. It performs the following steps:
- ~NOABRUPT `ResetQueue$A( コレ ) ◎ Perform ! ResetQueue(this).
- %result ~LET コレ.`cancelAlgorithm$rsdC( %reason ) ◎ Let result be the result of performing this.[[cancelAlgorithm]], passing reason.
- ~NOABRUPT `ReadableStreamDefaultControllerClearAlgorithms$A( コレ ) ◎ Perform ! ReadableStreamDefaultControllerClearAlgorithms(this).
- ~RET %result ◎ Return result.
`[[PullSteps]](readRequest)@rsdc は、 `PullSteps$sl の契約を実装する。 それは、次の手続きを遂行する: ◎ [[PullSteps]](readRequest) implements the [[PullSteps]] contract. It performs the following steps:
- %stream ~LET コレ.`stream$rsdC ◎ Let stream be this.[[stream]].
-
~IF[ コレ.`queue$rsdC は`空$でない ]: ◎ If this.[[queue]] is not empty,
- %chunk ~LET ~NOABRUPT `DequeueValue$A( コレ ) ◎ Let chunk be ! DequeueValue(this).
-
~IF[ コレ.`closeRequested$rsdC ~EQ ~T ]~AND[ コレ.`queue$rsdC は`空$である ] ◎ If this.[[closeRequested]] is true and this.[[queue]] is empty,
- ~NOABRUPT `ReadableStreamDefaultControllerClearAlgorithms$A( コレ ) ◎ Perform ! ReadableStreamDefaultControllerClearAlgorithms(this).
- ~NOABRUPT `ReadableStreamClose$A( %stream ) ◎ Perform ! ReadableStreamClose(stream).
- ~ELSE ⇒ ~NOABRUPT `ReadableStreamDefaultControllerCallPullIfNeeded$A( コレ ) ◎ Otherwise, perform ! ReadableStreamDefaultControllerCallPullIfNeeded(this).
- %readRequest の`~chunk手続き$rR( %chunk ) ◎ Perform readRequest’s chunk steps, given chunk.
-
~ELSE: ◎ Otherwise,
- ~NOABRUPT `ReadableStreamAddReadRequest$A( %stream ) ◎ Perform ! ReadableStreamAddReadRequest(stream, readRequest).
- ~NOABRUPT `ReadableStreamDefaultControllerCallPullIfNeeded$A( コレ ) ◎ Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(this).
`[[ReleaseSteps]]()@rsdc は、 `ReleaseSteps$sl の契約を実装する。 それは、次の手続きを遂行する: ◎ [[ReleaseSteps]]() implements the [[ReleaseSteps]] contract. It performs the following steps:
- ~RET ◎ Return.
4.7. `ReadableByteStreamController^I ~class
`ReadableByteStreamController$I ~classは、 `ReadableStream$I の状態と`内部~queue$の制御を許容する~methodたちを備える。 `可読~byte~stream$である `ReadableStream$I を構築するとき、 `下層~source$を操作するために,対応する `ReadableByteStreamController$I ~instanceが与えられる。 ◎ The ReadableByteStreamController class has methods that allow control of a ReadableStream's state and internal queue. When constructing a ReadableStream that is a readable byte stream, the underlying source is given a corresponding ReadableByteStreamController instance to manipulate.
4.7.1. ~interface定義
`ReadableByteStreamController$I ~class用の~Web~IDL定義は: ◎ The Web IDL definition for the ReadableByteStreamController class is given as follows:
[`Exposed$=*] interface `ReadableByteStreamController@I { readonly attribute `ReadableStreamBYOBRequest$I? `byobRequest$rbsc; readonly attribute `unrestricted double$? `desiredSize$rbsc; `undefined$ `close$rbsc(); `undefined$ `enqueue$rbsc(`ArrayBufferView$I %chunk); `undefined$ `error$rbsc(optional `any$ %e); };
4.7.2. 内部~slot
`ReadableByteStreamController$I の各~instanceは、 次に挙げる内部~slotを伴って作成される — 各項に与える記述は`規範的でない^em: ◎ Instances of ReadableByteStreamController are created with the internal slots described in the following table: ◎ Internal Slot|Description (non-normative)
- `autoAllocateChunkSize@rbsC
- `undefined^jv / 正な整数 ◎ A positive integer,\
- 自動的な~buffer割振り特能が可能化されたときは, ~bufferに割振る~sizeを指定する整数になり、 他の場合は `undefined^jv になる。 ◎ 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@rbsC
- ~NULL / ある `ReadableStreamBYOBRequest$I ◎ A ReadableStreamBYOBRequest instance\
- 現在の~BYOB~pull要請を表現する — そのような処理待ち要請が無い場合は ~NULL になる。 ◎ representing the current BYOB pull request, or null if there are no pending requests
- `cancelAlgorithm@rbsC
- 1 個の引数(取消n事由)をとり,~promiseを返す~algo ◎ A promise-returning algorithm, taking one argument (the cancel reason),\
- 要請された取消nを`下層~byte~source$へ通信する。 ◎ which communicates a requested cancelation to the underlying byte source
- `closeRequested@rbsC
- 真偽-~flag ◎ A boolean flag\
- 次に該当するかどうかを指示する ⇒ 当の~streamは,その`下層~byte~source$により~closeされたが、 その内部~queueには,まだ読取られていない`~chunk$がある。 ◎ 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
- `pullAgain@rbsC
- 真偽-~flag ◎ A boolean flag\
- 次のとき ~T に設定される ⇒ 更に~dataを~pullするために,~streamの仕組みにて`下層~byte~source$の~pull~algoを~callするよう要請されたが、 以前の~callがまだ実行-中にあるため,まだ~pullを行えない。 ◎ set to true if the stream’s mechanisms requested a call to the underlying byte source's pull algorithm to pull more data, but the pull could not yet be done since a previous call is still executing
- `pullAlgorithm@rbsC
- ~promiseを返す~algo ◎ A promise-returning algorithm\
- `下層~byte~source$から~dataを~pullする。 ◎ that pulls data from the underlying byte source
- `pulling@rbsC
- 真偽-~flag ◎ A boolean flag\
- 次の間, ~T に設定される ⇒ `下層~byte~source$の~pull~algoは実行-中にあり, それが返した~promiseは まだ充足されていない。 ◎ set to true while the underlying byte source's pull algorithm is executing and the returned promise has not yet fulfilled,\
- これは、 再入~callを防止するために利用される。 ◎ used to prevent reentrant calls
- `pendingPullIntos@rbsC
- `~pull~into記述子$たちが成す`~list$ ◎ A list of pull-into descriptors
- `queue@rbsC
- `可読~byte~stream用の~queue~entry$たちが成す`~list$ ◎ A list of readable byte stream queue entries\
- 当の~streamの[ `~chunk$たちが成す内部~queue ]を表現する。 ◎ representing the stream’s internal queue of chunks
- `queueTotalSize@rbsC
- `queue$rbsC 内に格納されている すべての~chunkの,~byte数による合計~size (`個別~size付き~queue$secを見よ)。 ◎ The total size, in bytes, of all the chunks stored in [[queue]] (see § 8.1 Queue-with-sizes)
- `started@rbsC
- 真偽-~flag ◎ A boolean flag\
- 当の~streamの`下層~byte~source$が開始処理【 `start()$usc 】を完遂したかどうかを指示する。 ◎ A boolean flag indicating whether the underlying byte source has finished starting
- `strategyHWM@rbsC
- ~number ◎ A number\
- 当の~streamの`~queuing策$の一部として,構築子に給されたもの。 その`下層~byte~source$には、 この~numberを境に`背圧$が適用されるようになる。 【 HWM = `High-Water Mark^en (`限界水位$) 】 ◎ 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
- `stream@rbsC
- ある `ReadableStream$I ◎ ↓
- この制御器により制御される`可読~stream$。 ◎ The ReadableStream instance controlled
注記: `ReadableByteStreamController$I の各~instanceは,[ `queue$rbsC, `queueTotalSize$rbsC ]両~slotを有するが、 これらに対しては,`個別~size付き~queue$secにおける ほとんどの抽象-演算は利用しない — この~queueを操作する仕方は、 仕様~内の他のものと~~異質なので。 代わりに, 2 つの~slotは、 手動で一緒に更新する。 ◎ Although ReadableByteStreamController instances have [[queue]] and [[queueTotalSize]] slots, we do not use most of the abstract operations in § 8.1 Queue-with-sizes 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.
`可読~byte~stream用の~queue~entry@ は、 次に挙げる`~item$sctからなる`構造体$であり, `可読~byte~stream$に特有な事例~用に`~chunk$を成す重要な側面を~capsule化する: ◎ A readable byte stream queue entry is a struct encapsulating the important aspects of a chunk for the specific case of readable byte streams. It has the following items:
- `~buffer@qE ◎ buffer
- ある `ArrayBuffer$I ◎ An ArrayBuffer,\
- `下層~byte~source$により元々給されたものの`転送され$た~versionになる。 ◎ which will be a transferred version of the one originally supplied by the underlying byte source
- `~byte~offset@qE ◎ byte offset
- 負でない整数 ◎ A nonnegative integer\
- `下層~byte~source$により元々給された~viewから導出された,~byte数による~offsetを与える。 ◎ number giving the byte offset derived from the view originally supplied by the underlying byte source
- `~byte長さ@qE ◎ byte length
- 負でない整数 ◎ A nonnegative integer\
- `下層~byte~source$により元々給された~viewから導出された,~byte数による長さを与える。 ◎ number giving the byte length derived from the view originally supplied by the underlying byte source
`~pull~into記述子@ は、 次に挙げる`~item$sctからなる`構造体$であり, 処理待ち~BYOB~pull要請を表現するために利用される: ◎ A pull-into descriptor is a struct used to represent pending BYOB pull requests. It has the following items:
- `~buffer@pD ◎ buffer
- ある `ArrayBuffer$I ◎ An ArrayBuffer
- `~buffer~byte長さ@pD ◎ buffer byte length
- 正な整数 ◎ A positive integer\
- `~buffer$pDの初期~byte長さを表現する。 ◎ representing the initial byte length of buffer
- `~byte~offset@pD ◎ byte offset
- 負でない整数 ◎ A nonnegative integer\
- `~buffer$pDの中を指す~byte~offset。 `下層~byte~source$は、 そこから書込みを開始することになる。 ◎ byte offset into the buffer where the underlying byte source will start writing
- `~byte長さ@pD ◎ byte length
- 正な整数 ◎ A positive integer\
- `~buffer$pDの中へ書込める~byte数。 ◎ number of bytes which can be written into the buffer
- `埋まった~byte数@pD ◎ bytes filled
- 負でない整数 ◎ A nonnegative integer\
- それまでに`~buffer$pDの中に書込まれた~byte数。 ◎ number of bytes that have been written into the buffer so far
- `最小な埋n@pD ◎ minimum fill
- 正な整数 ◎ A positive integer\
- 結付けられた `read()$byob 要請を充足する前に`~buffer$pDの中へ書込むことが要求される最小な~byte数を表現する。 既定では、 `要素~size$pDに等しくなる。 ◎ representing the minimum number of bytes that must be written into the buffer before the associated read() request may be fulfilled. By default, this equals the element size.
- `要素~size@pD ◎ element size
- 正な整数 ◎ A positive integer\
- `~view構築子$pDが述べる型の~viewを利用して,`~buffer$pDの中に一度に書込める~byte数を表現する。 ◎ representing the number of bytes that can be written into the buffer at a time, using views of the type described by the view constructor
- `~view構築子@pD ◎ view constructor
- `有型~配列~構築子@~TC39#table-49$ / ある `DataView$jI ◎ A typed array constructor or %DataView%,\
- [ `~buffer$pDの中に書込むために用いる【配列~buffer】~view ]を構築するときに利用されることになる。 ◎ which will be used for constructing a view with which to write into the buffer
- `読取器~型@pD ◎ reader type
- `default^l / `byob^l / `none^l ◎ ↓
- `none^l 以外は、 この要請を起動した`可読~stream読取器$の型を指示する。 ◎ Either "default" or "byob", indicating what type of readable stream reader initiated this request,\
- `none^l は、 起動した読取器が`解放-$されたことを指示する。 ◎ or "none" if the initiating reader was released
4.7.3. ~method/~prop
- %byobRequest = %controller.`byobRequest$rbsc
- 現在の~BYOB~pull要請は[ 在るならばそれ/ 無いならば ~NULL ]を返す。 ◎ Returns the current BYOB pull request, or null if there isn’t one.
- %desiredSize = %controller.`desiredSize$rbsc
- `desiredSize^rbsc 取得子は、 制御先の`~streamの内部~queueの残り~size$を返す。 それは、 負にもなり得る — ~queueを溢れた場合に。 [ `下層~byte~source$が`背圧$をいつどのように適用するか ]を決定するときは、 この情報が利用されるべきである。 ◎ Returns the desired size to fill the controlled stream’s internal queue. It can be negative, if the queue is over-full. An underlying byte source ought to use this information to determine when and how to apply backpressure.
- %controller.`close()$rbsc
- 制御先の可読~streamを~closeする。 `消費器$は,依然として[ それまでに~enqueueされた`~chunk$たちを~streamから読取れる ]が、 それらが読取られたなら,~streamは~closeされる。 ◎ Closes 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.
- %controller.`enqueue(chunk)$rbsc
- 所与の`~chunk$ %chunk を制御先の可読~stream内に~enqueueする。 %chunk には `ArrayBufferView$I の~instanceを与える必要があり、 さもなければ `TypeError$jE が投出されることになる。 ◎ Enqueues the given chunk chunk in the controlled readable stream. The chunk has to be an ArrayBufferView instance, or else a TypeError will be thrown.
- %controller.`error(e)$rbsc
- 制御先の可書~streamを~errorにする — 以降のヤリトリは、 すべて所与の~error %e で失敗させる。 ◎ Errors the controlled readable stream, making all future interactions with it fail with the given error e.
`byobRequest@rbsc 取得子~手続きは: ◎ The byobRequest getter steps are:
- ~RET ~NOABRUPT `ReadableByteStreamControllerGetBYOBRequest$A( コレ ) ◎ Return ! ReadableByteStreamControllerGetBYOBRequest(this).
`desiredSize@rbsc 取得子~手続きは: ◎ The desiredSize getter steps are:
- ~RET ~NOABRUPT `ReadableByteStreamControllerGetDesiredSize$A( コレ ) ◎ Return ! ReadableByteStreamControllerGetDesiredSize(this).
`close()@rbsc ~method手続きは: ◎ The close() method steps are:
- ~IF[ コレ.`closeRequested$rbsC ~EQ ~T ] ⇒ ~THROW `TypeError$jE ◎ If this.[[closeRequested]] is true, throw a TypeError exception.
- ~IF[ コレ.`stream$rbsC.`state$rS ~NEQ `readable^l ] ⇒ ~THROW `TypeError$jE ◎ If this.[[stream]].[[state]] is not "readable", throw a TypeError exception.
- ~ABRUPT `ReadableByteStreamControllerClose$A( コレ ) ◎ Perform ? ReadableByteStreamControllerClose(this).
`enqueue(chunk)@rbsc ~method手続きは: ◎ The enqueue(chunk) method steps are:
- ~IF[ %chunk.`ByteLength^sl ~EQ 0 ] ⇒ ~THROW `TypeError$jE ◎ If chunk.[[ByteLength]] is 0, throw a TypeError exception.
- ~IF[ %chunk.`ViewedArrayBuffer^sl.`ArrayBufferByteLength^sl ~EQ 0 ] ⇒ ~THROW `TypeError$jE ◎ If chunk.[[ViewedArrayBuffer]].[[ArrayBufferByteLength]] is 0, throw a TypeError exception.
- ~IF[ コレ.`closeRequested$rbsC ~EQ ~T ] ⇒ ~THROW `TypeError$jE ◎ If this.[[closeRequested]] is true, throw a TypeError exception.
- ~IF[ コレ.`stream$rbsC.`state$rS ~NEQ `readable^l ] ⇒ ~THROW `TypeError$jE ◎ If this.[[stream]].[[state]] is not "readable", throw a TypeError exception.
- ~RET ~ABRUPT `ReadableByteStreamControllerEnqueue$A( コレ, %chunk ) ◎ Return ? ReadableByteStreamControllerEnqueue(this, chunk).
`error(e)@rbsc ~method手続きは: ◎ The error(e) method steps are:
- ~NOABRUPT `ReadableByteStreamControllerError$A( コレ, %e ) ◎ Perform ! ReadableByteStreamControllerError(this, e).
4.7.4. 内部~method
各 `ReadableByteStreamController$I ~instanceは、 以下に与える内部~methodを実装する。 可読~streamの実装は、 `制御器との~interface法$secにて論じるように,[ それら, または 既定の制御器~用の それらに相当するもの ]いずれかを多形態的に~callすることになる。 ◎ The following are internal methods implemented by each ReadableByteStreamController instance. The readable stream implementation will polymorphically call to either these, or to their counterparts for default controllers, as discussed in § 4.9.2 Interfacing with controllers.
`[[CancelSteps]]( reason )@rbsc は、 `CancelSteps$sl の契約を実装する。 それは、次の手続きを遂行する: ◎ [[CancelSteps]](reason) implements the [[CancelSteps]] contract. It performs the following steps:
- ~NOABRUPT `ReadableByteStreamControllerClearPendingPullIntos$A( コレ ) ◎ Perform ! ReadableByteStreamControllerClearPendingPullIntos(this).
- ~NOABRUPT `ResetQueue$A( コレ ) ◎ Perform ! ResetQueue(this).
- %result ~LET コレ.`cancelAlgorithm$rbsC( %reason ) ◎ Let result be the result of performing this.[[cancelAlgorithm]], passing in reason.
- ~NOABRUPT `ReadableByteStreamControllerClearAlgorithms$A( コレ ) ◎ Perform ! ReadableByteStreamControllerClearAlgorithms(this).
- ~RET %result ◎ Return result.
`[[PullSteps]](readRequest)@rbsc は、 `PullSteps$sl の契約を実装する。 それは、次の手続きを遂行する: ◎ [[PullSteps]](readRequest) implements the [[PullSteps]] contract. It performs the following steps:
- %stream ~LET コレ.`stream$rbsC ◎ Let stream be this.[[stream]].
- ~Assert: ~NOABRUPT `ReadableStreamHasDefaultReader$A( %stream ) ~EQ ~T ◎ Assert: ! ReadableStreamHasDefaultReader(stream) is true.
-
~IF[ コレ.`queueTotalSize$rbsC ~GT 0 ]: ◎ If this.[[queueTotalSize]] > 0,
- ~Assert: ~NOABRUPT `ReadableStreamGetNumReadRequests$A( %stream ) ~EQ 0: ◎ Assert: ! ReadableStreamGetNumReadRequests(stream) is 0.
- ~NOABRUPT `ReadableByteStreamControllerFillReadRequestFromQueue$A( コレ, %readRequest) ◎ Perform ! ReadableByteStreamControllerFillReadRequestFromQueue(this, readRequest).
- ~RET ◎ Return.
- %autoAllocateChunkSize ~LET コレ.`autoAllocateChunkSize$rbsC ◎ Let autoAllocateChunkSize be this.[[autoAllocateChunkSize]].
-
~IF[ %autoAllocateChunkSize ~NEQ `undefined^jv ]: ◎ If autoAllocateChunkSize is not undefined,
- %buffer ~LET `Construct$Ax( `ArrayBuffer$jI, « %autoAllocateChunkSize » ) ◎ Let buffer be Construct(%ArrayBuffer%, « autoAllocateChunkSize »).
-
~IF[ %buffer は`中途完了^である ]: ◎ If buffer is an abrupt completion,
- %readRequest の`~error手続き$rR( %buffer.`Value^sl ) ◎ Perform readRequest’s error steps, given buffer.[[Value]].
- ~RET ◎ Return.
- %pullIntoDescriptor ~LET 次を伴う,新たな`~pull~into記述子$ ⇒# `~buffer$pD ~SET %buffer.`Value^sl, `~buffer~byte長さ$pD ~SET %autoAllocateChunkSize, `~byte~offset$pD ~SET 0, `~byte長さ$pD ~SET %autoAllocateChunkSize, `埋まった~byte数$pD ~SET 0, `最小な埋n$pD ~SET 1, `要素~size$pD ~SET 1, `~view構築子$pD ~SET `Uint8Array$jI, `読取器~型$pD ~SET `default^l ◎ Let pullIntoDescriptor be a new pull-into descriptor with ◎ buffer • buffer.[[Value]] buffer byte length • autoAllocateChunkSize byte offset • 0 byte length • autoAllocateChunkSize bytes filled • 0 minimum fill • 1 element size • 1 view constructor • %Uint8Array% reader type • "default"
- コレ.`pendingPullIntos$rbsC に %pullIntoDescriptor を`付加する$ ◎ Append pullIntoDescriptor to this.[[pendingPullIntos]].
- ~NOABRUPT `ReadableStreamAddReadRequest$A( %stream, %readRequest ) ◎ Perform ! ReadableStreamAddReadRequest(stream, readRequest).
- ~NOABRUPT `ReadableByteStreamControllerCallPullIfNeeded$A( コレ ) ◎ Perform ! ReadableByteStreamControllerCallPullIfNeeded(this).
`[[ReleaseSteps]]()@rbsc は、 `ReleaseSteps$sl の契約を実装する。 それは、次の手続きを遂行する: ◎ [[ReleaseSteps]]() implements the [[ReleaseSteps]] contract. It performs the following steps:
-
~IF[ コレ.`pendingPullIntos$rbsC は`空$でない ]: ◎ If this.[[pendingPullIntos]] is not empty,
- %firstPendingPullInto ~LET コレ.`pendingPullIntos$rbsC[ 0 ] ◎ Let firstPendingPullInto be this.[[pendingPullIntos]][0].
- %firstPendingPullInto の`読取器~型$pD ~SET `none^l ◎ Set firstPendingPullInto’s reader type to "none".
- コレ.`pendingPullIntos$rbsC ~SET « %firstPendingPullInto » ◎ Set this.[[pendingPullIntos]] to the list « firstPendingPullInto ».
4.8. `ReadableStreamBYOBRequest^I ~class
`ReadableStreamBYOBRequest$I ~classは、 `ReadableByteStreamController$I 内の[ 中へ~pullする要請 ]を表現する。 ◎ The ReadableStreamBYOBRequest class represents a pull-into request in a ReadableByteStreamController.
4.8.1. ~interface定義
`ReadableStreamBYOBRequest$I ~class用の~Web~IDL定義は: ◎ The Web IDL definition for the ReadableStreamBYOBRequest class is given as follows:
[`Exposed$=*] interface `ReadableStreamBYOBRequest@I { readonly attribute `ArrayBufferView$I? `view$bbrq; `undefined$ `respond$bbrq([`EnforceRange$] `unsigned long long$ %bytesWritten); `undefined$ `respondWithNewView$bbrq(`ArrayBufferView$I %view); };
4.8.2. 内部~slot
`ReadableStreamBYOBRequest$I の各~instanceは、 次に挙げる内部~slotを伴って作成される — 各項に与える記述は`規範的でない^em: ◎ Instances of ReadableStreamBYOBRequest are created with the internal slots described in the following table: ◎ Internal Slot|Description (non-normative)
- `controller@bbrQ
- 親の `ReadableByteStreamController$I ~instance ◎ The parent ReadableByteStreamController instance
- `view@bbrQ
- ある有型~配列 / ~NULL ◎ A typed array\
- 配列は、 当の制御器が生成された~dataを書込める行先~領域を表現する。 当の~BYOB要請が無効化されて以降は、 ~NULL になる。 ◎ representing the destination region to which the controller can write generated data, or null after the BYOB request has been invalidated.
4.8.3. ~method/~prop
- %view = %byobRequest.`view$bbrq
- 中に書込むための~viewを返す — 当の~BYOB要請は すでに応答していた場合、 ~NULL を返す。 ◎ Returns the view for writing in to, or null if the BYOB request has already been responded to.
- %byobRequest.`respond(bytesWritten)$bbrq
- 結付けられた`可読~byte~stream$に次を指示する ⇒ `view$bbrq の中へは %bytesWritten 個の~byteが書込んで【!were written】,その結果を`消費器$に表面化させる ◎ Indicates to the associated readable byte stream that bytesWritten bytes were written into view, causing the result be surfaced to the consumer.
- この~methodが~callされた後には、 `view$bbrq は`転送され$,もはや改変-可能でなくなる。 ◎ After this method is called, view will be transferred and no longer modifiable.
- %byobRequest.`respondWithNewView(view)$bbrq
- 結付けられた`可読~byte~stream$に次を指示する ⇒ `view$bbrq の中へ書込む代わりに、 `下層~byte~source$は 新たな `ArrayBufferView$I を供して【!is providing】, それを`可読~byte~stream$の`消費器$に与える。 ◎ Indicates to the associated readable byte stream that instead of writing into view, the underlying byte source is providing a new ArrayBufferView, which will be given to the consumer of the readable byte stream.
-
新たな %view は、 `view$bbrq と同じ裏~memory領域への~viewになるはずである — すなわち,次を満たすようになる:
- その~bufferは `view$bbrq の~bufferに等しい【同じ?】(または,その `TransferArrayBuffer$A ~versionである)
- その `byteOffset^c は `view$bbrq の `byteOffset^c に等しい
- その `byteLength^c (書込まれた~byte数を表現する)は `view$bbrq の `byteLength^c 以下である
- この~methodが~callされた後には、 %view は`転送され$,もはや改変-可能でなくなる。 ◎ After this method is called, view will be transferred and no longer modifiable.
`view@bbrq 取得子~手続きは: ◎ The view getter steps are:
- ~RET コレ.`view$bbrQ ◎ Return this.[[view]].
`respond(bytesWritten)@bbrq ~method手続きは: ◎ The respond(bytesWritten) method steps are:
- ~IF[ コレ.`controller$bbrQ ~EQ `undefined^jv ] ⇒ ~THROW `TypeError$jE ◎ If this.[[controller]] is undefined, throw a TypeError exception.
- ~IF[ ~NOABRUPT `IsDetachedBuffer$Ax( コレ.`view$bbrQ.`ArrayBuffer^sl ) ~EQ ~T ] ⇒ ~THROW `TypeError$jE ◎ If ! IsDetachedBuffer(this.[[view]].[[ArrayBuffer]]) is true, throw a TypeError exception.
- ~Assert: コレ.`view$bbrQ.`ByteLength^sl ~GT 0 ◎ Assert: this.[[view]].[[ByteLength]] > 0.
- ~Assert: コレ.`view$bbrQ.`ViewedArrayBuffer^sl.`ByteLength^sl ~GT 0 ◎ Assert: this.[[view]].[[ViewedArrayBuffer]].[[ByteLength]] > 0.
- ~ABRUPT `ReadableByteStreamControllerRespond$A( コレ.`controller$bbrQ, %bytesWritten ) ◎ Perform ? ReadableByteStreamControllerRespond(this.[[controller]], bytesWritten).
`respondWithNewView(view)@bbrq ~method手続きは: ◎ The respondWithNewView(view) method steps are:
- ~IF[ コレ.`controller$bbrQ ~EQ `undefined^jv ] ⇒ ~THROW `TypeError$jE ◎ If this.[[controller]] is undefined, throw a TypeError exception.
- ~IF[ ~NOABRUPT `IsDetachedBuffer$Ax( %view.`ViewedArrayBuffer^sl)~EQ ~T ] ⇒ ~THROW `TypeError$jE ◎ If ! IsDetachedBuffer(view.[[ViewedArrayBuffer]]) is true, throw a TypeError exception.
- ~RET ~ABRUPT `ReadableByteStreamControllerRespondWithNewView$A( コレ.`controller$bbrQ, %view) ◎ Return ? ReadableByteStreamControllerRespondWithNewView(this.[[controller]], view).
4.9. 抽象-演算
4.9.1. 可読~streamとの作業-法
以下に与える抽象-演算は、 `ReadableStream$I ~instanceに対し高~levelから演算する。 ◎ The following abstract operations operate on ReadableStream instances at a higher level.
`AcquireReadableStreamBYOBReader(stream)@A は、次の手続きを遂行する: ◎ AcquireReadableStreamBYOBReader(stream) performs the following steps:
- %reader ~LET `新たな$ `ReadableStreamBYOBReader$I ◎ Let reader be a new ReadableStreamBYOBReader.
- ~ABRUPT `SetUpReadableStreamBYOBReader$A( %reader, « %stream » ) ◎ Perform ? SetUpReadableStreamBYOBReader(reader, stream).
- ~RET %reader ◎ Return reader.
`AcquireReadableStreamDefaultReader(stream)@A は、次の手続きを遂行する: ◎ AcquireReadableStreamDefaultReader(stream) performs the following steps:
- %reader ~LET `新たな$ `ReadableStreamDefaultReader$I ◎ Let reader be a new ReadableStreamDefaultReader.
- ~ABRUPT `SetUpReadableStreamDefaultReader$A( %reader, « %stream » ) ◎ Perform ? SetUpReadableStreamDefaultReader(reader, stream).
- ~RET %reader ◎ Return reader.
`CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm[, highWaterMark[, sizeAlgorithm ] ])@A は、次の手続きを遂行する: ◎ CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm[, highWaterMark, [, sizeAlgorithm]]) performs the following steps:
- ~IF[ %highWaterMark は渡されていない ] ⇒ %highWaterMark ~SET 1 ◎ If highWaterMark was not passed, set it to 1.
- ~IF[ %sizeAlgorithm は渡されていない ] ⇒ %sizeAlgorithm ~SET 次を走らす~algo ⇒ ~RET 1 ◎ If sizeAlgorithm was not passed, set it to an algorithm that returns 1.
- ~Assert: ~NOABRUPT `IsNonNegativeNumber$A( %highWaterMark ) ~EQ ~T ◎ Assert: ! IsNonNegativeNumber(highWaterMark) is true.
- %stream ~LET `新たな$ `ReadableStream$I ◎ Let stream be a new ReadableStream.
- ~NOABRUPT `InitializeReadableStream$A( %stream ) ◎ Perform ! InitializeReadableStream(stream).
- %controller ~LET `新たな$ `ReadableStreamDefaultController$I ◎ Let controller be a new ReadableStreamDefaultController.
- ~ABRUPT `SetUpReadableStreamDefaultController$A( ↓ ) ⇒# %stream, %controller, %startAlgorithm, %pullAlgorithm, %cancelAlgorithm, %highWaterMark, %sizeAlgorithm ◎ Perform ? SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm).
- ~RET %stream ◎ Return stream.
注記: この抽象-演算は、 給された %startAlgorithm が投出するとき, そのときに限り, 例外を投出することになる。 ◎ This abstract operation will throw an exception if and only if the supplied startAlgorithm throws.
`CreateReadableByteStream(startAlgorithm, pullAlgorithm, cancelAlgorithm)@A は、次の手続きを遂行する: ◎ CreateReadableByteStream(startAlgorithm, pullAlgorithm, cancelAlgorithm) performs the following steps:
- %stream ~LET `新たな$ `ReadableStream$I ◎ Let stream be a new ReadableStream.
- ~NOABRUPT `InitializeReadableStream$A( %stream ) ◎ Perform ! InitializeReadableStream(stream).
- %controller ~LET `新たな$ `ReadableByteStreamController$I ◎ Let controller be a new ReadableByteStreamController.
- ~ABRUPT `SetUpReadableByteStreamController$A( %stream, %controller, %startAlgorithm, %pullAlgorithm, %cancelAlgorithm, 0, `undefined^jv ) ◎ Perform ? SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, 0, undefined).
- ~RET %stream ◎ Return stream.
注記: この抽象-演算は、 給された %startAlgorithm が投出するとき, そのときに限り, 例外を投出することになる。 ◎ This abstract operation will throw an exception if and only if the supplied startAlgorithm throws.
`InitializeReadableStream(stream)@A は、次の手続きを遂行する: ◎ InitializeReadableStream(stream) performs the following steps:
- %stream の ⇒# .`state$rS ~SET `readable^l, .`reader$rS ~SET `undefined^jv, .`storedError$rS ~SET `undefined^jv, .`disturbed$rS ~SET ~F ◎ Set stream.[[state]] to "readable". ◎ Set stream.[[reader]] and stream.[[storedError]] to undefined. ◎ Set stream.[[disturbed]] to false.
`IsReadableStreamLocked(stream)@A は、次の手続きを遂行する: ◎ IsReadableStreamLocked(stream) performs the following steps:
- ~IF[ %stream.`reader$rS ~EQ `undefined^jv ] ⇒ ~RET ~F ◎ If stream.[[reader]] is undefined, return false.
- ~RET ~T ◎ Return true.
`ReadableStreamFromIterable(asyncIterable)@A は、 次の手続きを遂行する: ◎ ReadableStreamFromIterable(asyncIterable) performs the following steps:
- %stream ~LET `undefined^jv ◎ Let stream be undefined.
- %iteratorRecord ~LET ~ABRUPT `GetIterator$Ax( %asyncIterable, `async^i ) ◎ Let iteratorRecord be ? GetIterator(asyncIterable, async).
- %startAlgorithm ~LET 次を走らす~algo ⇒ ~RET `undefined^jv ◎ Let startAlgorithm be an algorithm that returns undefined.
-
%pullAlgorithm ~LET 次を走らす~algo: ◎ Let pullAlgorithm be the following steps:
- %nextResult ~LET `IteratorNext$Ax( %iteratorRecord ) ◎ Let nextResult be IteratorNext(iteratorRecord).
- ~IF[ %nextResult は`中途完了^である ] ⇒ ~RET `却下される~promise$( %nextResult.`Value^sl ) ◎ If nextResult is an abrupt completion, return a promise rejected with nextResult.[[Value]].
- %nextPromise ~LET `解決される~promise$( %nextResult.`Value^sl ) ◎ Let nextPromise be a promise resolved with nextResult.[[Value]].
-
~RET `~promiseに反応する$( %nextPromise ) — 次を与える下で: ◎ Return the result of reacting to nextPromise with\
-
`充足~手続き^i は、 所与の ( %iterResult ) に対し: ◎ the following fulfillment steps, given iterResult:
- ~IF[ %iterResult は `Object$jt でない ] ⇒ ~THROW `TypeError$jE ◎ If iterResult is not an Object, throw a TypeError.
- %done ~LET ~ABRUPT `IteratorComplete$Ax( %iterResult ) ◎ Let done be ? IteratorComplete(iterResult).
- ~IF[ %done ~EQ ~T ] ⇒ ~NOABRUPT `ReadableStreamDefaultControllerClose$A( %stream.`controller$rS ) ◎ If done is true: • Perform ! ReadableStreamDefaultControllerClose(stream.[[controller]]).
-
~ELSE: ◎ Otherwise:
- %value ~LET ~ABRUPT `IteratorValue$Ax( %iterResult ) ◎ Let value be ? IteratorValue(iterResult).
- ~NOABRUPT `ReadableStreamDefaultControllerEnqueue$A( %stream.`controller$rS, %value ) ◎ Perform ! ReadableStreamDefaultControllerEnqueue(stream.[[controller]], value).
-
-
%cancelAlgorithm ~LET 所与の ( %reason ) に対し,次を走らす~algo: ◎ Let cancelAlgorithm be the following steps, given reason:
- %iterator ~LET %iteratorRecord.`Iterator^sl ◎ Let iterator be iteratorRecord.[[Iterator]].
- %returnMethod ~LET `GetMethod$Ax( %iterator, `return^l ) ◎ Let returnMethod be GetMethod(iterator, "return").
- ~IF[ %returnMethod は`中途完了^である ] ⇒ ~RET `却下される~promise$( %returnMethod.`Value^sl ) ◎ If returnMethod is an abrupt completion, return a promise rejected with returnMethod.[[Value]].
- ~IF[ %returnMethod.`Value^sl ~EQ `undefined^jv ] ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ If returnMethod.[[Value]] is undefined, return a promise resolved with undefined.
- %returnResult ~LET `Call$Ax( %returnMethod.`Value^sl, %iterator, « %reason » ) ◎ Let returnResult be Call(returnMethod.[[Value]], iterator, « reason »).
- ~IF[ %returnResult は`中途完了^である ] ⇒ ~RET `却下される~promise$( %returnResult.`Value^sl ) ◎ If returnResult is an abrupt completion, return a promise rejected with returnResult.[[Value]].
- %returnPromise ~LET `解決される~promise$( %returnResult.`Value^sl ) ◎ Let returnPromise be a promise resolved with returnResult.[[Value]].
-
~RET `~promiseに反応する$( %returnPromise ) — 次を与える下で: ◎ Return the result of reacting to returnPromise with\
-
`充足~手続き^i は、 所与の ( %iterResult ) に対し: ◎ the following fulfillment steps, given iterResult:
- ~IF[ %iterResult は `Object$jt でない ] ⇒ ~THROW `TypeError$jE ◎ If iterResult is not an Object, throw a TypeError.
- ~RET `undefined^jv ◎ Return undefined.
-
- %stream ~SET ~NOABRUPT `CreateReadableStream$A( %startAlgorithm, %pullAlgorithm, %cancelAlgorithm, 0 ) ◎ Set stream to ! CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm, 0).
- ~RET %stream ◎ Return stream.
`ReadableStreamPipeTo(source, dest, preventClose, preventAbort, preventCancel[, signal])@A は、次の手続きを遂行する: ◎ ReadableStreamPipeTo(source, dest, preventClose, preventAbort, preventCancel[, signal]) performs the following steps:
- ~Assert: %source は `ReadableStream$I を`実装する$ ◎ Assert: source implements ReadableStream.
- ~Assert: %dest は `WritableStream$I を`実装する$ ◎ Assert: dest implements WritableStream.
- ~Assert: [ %preventClose, %preventAbort, %preventCancel ]は、 どれも真偽値である ◎ Assert: preventClose, preventAbort, and preventCancel are all booleans.
- ~IF[ %signal は与えられていない ] ⇒ %signal ~SET `undefined^jv ◎ If signal was not given, let signal be undefined.
- ~Assert: [ %signal ~EQ `undefined^jv ]~OR[ %signal は `AbortSignal$I を`実装する$ ] ◎ Assert: either signal is undefined, or signal implements AbortSignal.
- ~Assert: ~NOABRUPT `IsReadableStreamLocked$A( %source ) ~EQ ~F ◎ Assert: ! IsReadableStreamLocked(source) is false.
- ~Assert: ~NOABRUPT `IsWritableStreamLocked$A( %dest ) ~EQ ~F ◎ Assert: ! IsWritableStreamLocked(dest) is false.
- %reader ~LET ε ◎ ↓
- ~IF[ %source は `ReadableByteStreamController$I を`実装する$ ] ⇒ %reader ~SET ~UAの裁量で,次のいずれかを遂行した結果 ⇒# ~NOABRUPT `AcquireReadableStreamBYOBReader$A( %source ) / ~NOABRUPT `AcquireReadableStreamDefaultReader$A( %source ) ◎ If source.[[controller]] implements ReadableByteStreamController, let reader be either ! AcquireReadableStreamBYOBReader(source) or ! AcquireReadableStreamDefaultReader(source), at the user agent’s discretion.
- ~ELSE ⇒ %reader ~SET ~NOABRUPT `AcquireReadableStreamDefaultReader$A( %source ) ◎ Otherwise, let reader be ! AcquireReadableStreamDefaultReader(source).
- %writer ~LET ~NOABRUPT `AcquireWritableStreamDefaultWriter$A( %dest ) ◎ Let writer be ! AcquireWritableStreamDefaultWriter(dest).
- %source.`disturbed$rS ~SET ~T ◎ Set source.[[disturbed]] to true.
- %shuttingDown ~LET ~F ◎ Let shuttingDown be false.
- %promise ~LET `新たな~promise$ ◎ Let promise be a new promise.
-
~IF[ %signal ~NEQ `undefined^jv ]: ◎ If signal is not undefined,
-
%abortAlgorithm ~LET 次を走らす~algo: ◎ Let abortAlgorithm be the following steps:
- %error ~LET %signal の`中止-事由$aB ◎ Let error be signal’s abort reason.
- %actions ~LET 新たな`有順序~集合$ ◎ Let actions be an empty ordered set.
-
~IF[ %preventAbort ~EQ ~F ]: ◎ If preventAbort is false,\
-
%actions に次を走らす動作を`付加する$set: ◎ append the following action to actions:
- ~IF[ %dest.`state$wS ~EQ `writable^l ] ⇒ ~RET ~NOABRUPT `WritableStreamAbort$A( %dest, %error ) ◎ If dest.[[state]] is "writable", return ! WritableStreamAbort(dest, error).
- ~RET `解決される~promise$( `undefined^jv ) ◎ Otherwise, return a promise resolved with undefined.
-
-
~IF[ %preventCancel ~EQ ~F ]: ◎ If preventCancel is false,\
-
%actions に次を走らす動作を`付加する$set: ◎ append the following action to actions:
- ~IF[ %source.`state$rS ~EQ `readable^l ] ⇒ ~RET ~NOABRUPT `ReadableStreamCancel$A( %source, %error ) ◎ If source.[[state]] is "readable", return ! ReadableStreamCancel(source, error).
- ~RET `解決される~promise$( `undefined^jv ) ◎ Otherwise, return a promise resolved with undefined.
-
- `~shutdownする$( %error, 次を走らす動作 ) ⇒ `すべてを待機する~promiseを取得する$( %actions 内の動作たち ) ◎ Shutdown with an action consisting of getting a promise to wait for all of the actions in actions, and with error.
- ~IF[ %signal は`中止-済み$aBである ] ⇒# %abortAlgorithm を遂行する; ~RET %promise ◎ If signal is aborted, perform abortAlgorithm and return promise.
- `通達に~algoを追加する$( %signal, %abortAlgorithm ) ◎ Add abortAlgorithm to signal.
-
-
( %reader, %writer ) を利用して,`並列的$に 本当はそうでない — `課題 #905@https://github.com/whatwg/streams/issues/905$ を見よ — %source から すべての`~chunk$を読取って %dest に書込む。 これが起こる正確な方式は、 ( 読取器, 書込器 ) が供する~lock法に因り,作者~codeからは観測-可能でない。 よって,~UAには これを柔軟に行う余地があるが、 利用される正確な~algoを問わず,以下の拘束が適用される: ◎ In parallel but not really; see #905, using reader and writer, read all chunks from source 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:
- `公な~APIは利用しないモノトスル^strong: — [ 読取り/書込み ]の間, および 以下に挙げる演算を遂行している間は、 何かを改変-可能な~JSの[ 読取器, 書込器, ~stream~API ](すなわち,適切な~prototype上の~methodたち)は,利用しないモノトスル — ~streamは,直に操作するモノトスル。 ◎ 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.
-
`背圧は施行するモノトスル^strong — ~UAは: ◎ Backpressure must be enforced:
- `WritableStreamDefaultWriterGetDesiredSize$A( %writer ) の結果が[ 0 以下, または ~NULL ]になる間は、 %reader から読取らないモノトスル ◎ 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 as a basis to determine the size of the chunks read from reader.
注記: 小さすぎる/大きすぎる~chunkたちを読取るのは、 効率的でないことが多い。 他の情報も,最適な~chunk~sizeを決定する要因になるかもしれない。 ◎ It’s frequently inefficient to read chunks that are too small or too large. Other information might be factored in to determine the optimal chunk size.
-
読取nや書込nは、 背圧~通達~以外の理由で遅延されるべきでない。 ◎ Reads or writes should not be delayed for reasons other than these backpressure signals.
次回の 読取n/書込n 演算を続行する前に,各 書込nが成功裡に完了するのを待機するような実装は、 この推奨に違反する。 そのような実装では、 %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は活動を停止させるモノトスル^strong — %shuttingDown が ~T になって以降は、 ~UAは,それ以上 %reader からの読取nを起動しないモノトスル。 また、 以下に述べるように, すでに読取られた~chunkの書込nのみを遂行するモノトスル。 特に,~UAは、[ 読取n/書込n ]を遂行する前に,以下の条件を検査するモノトスル — それらは、 即時に~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状態は伝播するモノトスル^strong — 以下の条件は、 挙げられた順に適用するモノトスル: ◎ Error and close states must be propagated: the following conditions must be applied in order.
-
`~errorは前方へ伝播するモノトスル^strong — %source.`state$rS ~EQ `errored^l のとき, または そうなったときは: ◎ Errors must be propagated forward: if source.[[state]] is or becomes "errored", then
- ~IF[ %preventAbort ~EQ ~F ] ⇒ `~shutdownする$( %source.`storedError$rS, 次を行う動作 ) ⇒ ~NOABRUPT `WritableStreamAbort$A( %dest, %source.`storedError$rS ) ◎ If preventAbort is false, shutdown with an action of ! WritableStreamAbort(dest, source.[[storedError]]) and with source.[[storedError]].
- ~ELSE ⇒ `~shutdownする$( %source.`storedError$rS, ε ) ◎ Otherwise, shutdown with source.[[storedError]].
-
`~errorは後方へ伝播するモノトスル^strong — %dest.`state$wS ~EQ `errored^l のとき, または そうなったときは: ◎ Errors must be propagated backward: if dest.[[state]] is or becomes "errored", then
- ~IF[ %preventCancel ~EQ ~F ] ⇒ `~shutdownする$( %dest.`storedError$wS, 次を行う動作 ) ⇒ ~NOABRUPT `ReadableStreamCancel$A( %source, %dest.`storedError$wS ) ◎ If preventCancel is false, shutdown with an action of ! ReadableStreamCancel(source, dest.[[storedError]]) and with dest.[[storedError]].
- ~ELSE ⇒ `~shutdownする$( %dest.`storedError$wS, ε ) ◎ Otherwise, shutdown with dest.[[storedError]].
-
`~closingは前方へ伝播するモノトスル^strong — %source.`state$rS ~EQ `closed^l のとき, または そうなったときは: ◎ Closing must be propagated forward: if source.[[state]] is or becomes "closed", then
- ~IF[ %preventClose ~EQ ~F ] ⇒ `~shutdownする$( ε, 次を行う動作 ) ⇒ ~NOABRUPT `WritableStreamDefaultWriterCloseWithErrorPropagation$A( %writer ) ◎ If preventClose is false, shutdown with an action of ! WritableStreamDefaultWriterCloseWithErrorPropagation(writer).
- ~ELSE ⇒ `~shutdownする$( ε, ε ) ◎ Otherwise, shutdown.
-
`~closingは後方へ伝播するモノトスル^strong — [ ~NOABRUPT `WritableStreamCloseQueuedOrInFlight$A( %dest ) ~EQ ~T ]~OR[ %dest.`state$wS ~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$jE ◎ Let destClosed be a new TypeError.
- ~IF[ %preventCancel ~EQ ~F ] ⇒ `~shutdownする$( %destClosed, 次を行う動作 ) ⇒ ~NOABRUPT `ReadableStreamCancel$A( %source, %destClosed ) ◎ If preventCancel is false, shutdown with an action of ! ReadableStreamCancel(source, 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 ~T ] ⇒ ~RET ◎ If shuttingDown is true, abort these substeps.
- %shuttingDown ~SET ~T ◎ Set shuttingDown to true.
-
~IF[ %dest.`state$wS ~EQ `writable^l ]~AND[ ~NOABRUPT `WritableStreamCloseQueuedOrInFlight$A( %dest ) ~EQ ~F ]: ◎ 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:
- ~NOABRUPT `WritableStreamDefaultWriterRelease$A( %writer ) ◎ Perform ! WritableStreamDefaultWriterRelease(writer).
- ~IF[ %reader は `ReadableStreamBYOBReader$I を`実装する$ ] ⇒ ~NOABRUPT `ReadableStreamBYOBReaderRelease$A( %reader ) ◎ If reader implements ReadableStreamBYOBReader, perform ! ReadableStreamBYOBReaderRelease(reader).
- ~ELSE ⇒ ~NOABRUPT `ReadableStreamDefaultReaderRelease$A( %reader ) ◎ Otherwise, perform ! ReadableStreamDefaultReaderRelease(reader).
- ~IF[ %signal ~NEQ `undefined^jv ] ⇒ `通達から~algoを除去する$( %signal, %abortAlgorithm ) ◎ If signal is not undefined, remove abortAlgorithm from signal.
- ~IF[ %error ~NEQ ε ] ⇒ `~promiseを却下する$( %promise, %error ) ◎ If error was given, reject promise with error.
- ~ELSE ⇒ `~promiseを解決する$( %promise, `undefined^jv ) ◎ 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.
`ReadableStreamTee(stream, cloneForBranch2)@A は、 所与の可読~streamを`二叉化-$する。 ◎ ReadableStreamTee(stream, cloneForBranch2) will tee a given readable stream.
2 個目の引数 %cloneForBranch2 は、[ 元の~streamからの~dataは、 2 個目の分岐~内に現れる前に~cloneされるかどうか ]を統治する( `HTML$r による,`直列化-可能$な~obj用の~frameworkを利用して)。 これは、 両 分岐が消費されるとき,[ ~chunkを`転送する@~HTMLcloning#transferable-objects$ことにより, 互いに干渉しあうおそれがある局面 ]で有用になる。 しかしながら、[ 両 分岐の間に外から見える非対称性 ]も導入され, アリな`~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]
%stream は`可読~byte~stream$である場合、 %cloneForBranch2 は無視され,各~chunkは無条件に~cloneされる。 ◎ If stream is a readable byte stream, then cloneForBranch2 is ignored and chunks are cloned unconditionally.
注記: この標準においては、 `ReadableStreamTee$A が~callされるときは, 常に %cloneForBranch2 は ~F に設定される。 他の仕様は、 二叉化-を包装する~algoを介して ~T を渡す。 ◎ In this standard ReadableStreamTee is always called with cloneForBranch2 set to false; other specifications pass true via the tee wrapper algorithm.
それは、次の手続きを遂行する: ◎ It performs the following steps:
- ~Assert: %stream は `ReadableStream$I を`実装する$ ◎ Assert: stream implements ReadableStream.
- ~Assert: %cloneForBranch2 は真偽値である ◎ Assert: cloneForBranch2 is a boolean.
- ~IF[ %stream.`controller$rS は `ReadableByteStreamController$I を`実装する$ ] ⇒ ~RET ~ABRUPT `ReadableByteStreamTee$A( %stream ) ◎ If stream.[[controller]] implements ReadableByteStreamController, return ? ReadableByteStreamTee(stream).
- ~RET ~ABRUPT `ReadableStreamDefaultTee$A( %stream, %cloneForBranch2 ) ◎ Return ? ReadableStreamDefaultTee(stream, cloneForBranch2).
`ReadableStreamDefaultTee(stream, cloneForBranch2)@A は、次の手続きを遂行する: ◎ ReadableStreamDefaultTee(stream, cloneForBranch2) performs the following steps:
- ~Assert: %stream は `ReadableStream$I を`実装する$ ◎ Assert: stream implements ReadableStream.
- ~Assert: %cloneForBranch2 は真偽値である ◎ Assert: cloneForBranch2 is a boolean.
- %reader ~LET ~ABRUPT `AcquireReadableStreamDefaultReader$A( %stream ) ◎ Let reader be ? AcquireReadableStreamDefaultReader(stream).
- %reading ~LET ~F ◎ Let reading be false.
- %readAgain ~LET ~F ◎ Let readAgain be false.
- %canceled1 ~LET ~F ◎ Let canceled1 be false.
- %canceled2 ~LET ~F ◎ Let canceled2 be false.
- %reason1 ~LET `undefined^jv ◎ Let reason1 be undefined.
- %reason2 ~LET `undefined^jv ◎ Let reason2 be undefined.
- %branch1 ~LET `undefined^jv ◎ Let branch1 be undefined.
- %branch2 ~LET `undefined^jv ◎ Let branch2 be undefined.
- %cancelPromise ~LET `新たな~promise$ ◎ Let cancelPromise be a new promise.
-
%pullAlgorithm ~LET 次を走らす~algo: ◎ Let pullAlgorithm be the following steps:
-
~IF[ %reading ~EQ ~T ]: ◎ If reading is true,
- %readAgain ~SET ~T ◎ Set readAgain to true.
- ~RET `解決される~promise$( `undefined^jv ) ◎ Return a promise resolved with undefined.
- %reading ~SET ~T ◎ Set reading to true.
-
%readRequest ~LET 次に挙げる`~item$sctを伴う,`読取n要請$: ◎ Let readRequest be a read request with the following items:
-
`~chunk手続き$rRは、 所与の ( %chunk ) に対し ⇒ `小taskを~queueする$( 次の手続き ) ◎ chunk steps, given chunk • Queue a microtask to perform\
手続きは: ◎ the following steps:
- %readAgain ~SET ~F ◎ Set readAgain to false.
- %chunk1 ~LET %chunk ◎ ↓
- %chunk2 ~LET %chunk ◎ Let chunk1 and chunk2 be chunk.
-
~IF[ %canceled2 ~EQ ~F ]~AND[ %cloneForBranch2 ~EQ ~T ]: ◎ If canceled2 is false and cloneForBranch2 is true,
- %cloneResult ~LET `StructuredClone$A( %chunk2 ) ◎ Let cloneResult be StructuredClone(chunk2).
-
~IF[ %cloneResult は`中途完了^である ]: ◎ If cloneResult is an abrupt completion,
- ~NOABRUPT `ReadableStreamDefaultControllerError$A( %branch1.`controller$rS, %cloneResult.`Value^sl ) ◎ Perform ! ReadableStreamDefaultControllerError(branch1.[[controller]], cloneResult.[[Value]]).
- ~NOABRUPT `ReadableStreamDefaultControllerError$A( %branch2.`controller$rS, %cloneResult.`Value^sl ) ◎ Perform ! ReadableStreamDefaultControllerError(branch2.[[controller]], cloneResult.[[Value]]).
- `~promiseを解決する$( %cancelPromise, 次の結果 ) ⇒ ~NOABRUPT `ReadableStreamCancel$A( %stream, %cloneResult.`Value^sl ) ◎ Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]).
- ~RET ◎ Return.
- ~ELSE ⇒ %chunk2 ~SET %cloneResult.`Value^sl ◎ Otherwise, set chunk2 to cloneResult.[[Value]].
- ~IF[ %canceled1 ~EQ ~F ] ⇒ ~NOABRUPT `ReadableStreamDefaultControllerEnqueue$A( %branch1.`controller$rS, %chunk1 ) ◎ If canceled1 is false, perform ! ReadableStreamDefaultControllerEnqueue(branch1.[[controller]], chunk1).
- ~IF[ %canceled2 ~EQ ~F ] ⇒ ~NOABRUPT `ReadableStreamDefaultControllerEnqueue$A( %branch2.`controller$rS, %chunk2 ) ◎ If canceled2 is false, perform ! ReadableStreamDefaultControllerEnqueue(branch2.[[controller]], chunk2).
- %reading ~SET ~F ◎ Set reading to false.
- ~IF[ %readAgain ~EQ ~T ] ⇒ %pullAlgorithm を遂行する ◎ If readAgain is true, perform pullAlgorithm.
注記: ここでの小taskによる遅延は、 必要yである — 下にて %reader.`closedPromise$rsR を利用するとき、 少なくとも,~errorを検出する小taskがかかるので。 %stream における~errorは,両~分岐とも即時に~errorにすることが求まれるので、 非同期的に可用な~errorに先んじて,成功裡な読取nを同期的に可用にするわけにはいかない。 ◎ The microtask delay here is necessary because it takes at least a microtask to detect errors, when we use reader.[[closedPromise]] below. We want errors in stream to error both branches immediately, so we cannot let successful synchronously-available reads happen ahead of asynchronously-available errors.
-
`~close手続き$rRは: ◎ close steps
- %reading ~SET ~F ◎ Set reading to false.
- ~IF[ %canceled1 ~EQ ~F ] ⇒ ~NOABRUPT `ReadableStreamDefaultControllerClose$A( %branch1.`controller$rS ) ◎ If canceled1 is false, perform ! ReadableStreamDefaultControllerClose(branch1.[[controller]]).
- ~IF[ %canceled2 ~EQ ~F ] ⇒ ~NOABRUPT `ReadableStreamDefaultControllerClose$A( %branch2.`controller$rS ) ◎ If canceled2 is false, perform ! ReadableStreamDefaultControllerClose(branch2.[[controller]]).
- ~IF[ %canceled1 ~EQ ~F ]~OR[ %canceled2 ~EQ ~F ] ⇒ `~promiseを解決する$( %cancelPromise, `undefined^jv ) ◎ If canceled1 is false or canceled2 is false, resolve cancelPromise with undefined.
- `~error手続き$rRは ⇒ %reading ~SET ~F ◎ error steps • Set reading to false.
-
- ~NOABRUPT `ReadableStreamDefaultReaderRead$A( %reader, %readRequest ) ◎ Perform ! ReadableStreamDefaultReaderRead(reader, readRequest).
- ~RET `解決される~promise$( `undefined^jv ) ◎ Return a promise resolved with undefined.
-
-
%cancel1Algorithm ~LET 所与の ( %reason ) に対し,次を走らす~algo: ◎ Let cancel1Algorithm be the following steps, taking a reason argument:
- %canceled1 ~SET ~T ◎ Set canceled1 to true.
- %reason1 ~SET %reason ◎ Set reason1 to reason.
-
~IF[ %canceled2 ~EQ ~T ]: ◎ If canceled2 is true,
- %compositeReason ~LET ~NOABRUPT `CreateArrayFromList$Ax( « %reason1, %reason2 » ) ◎ Let compositeReason be ! CreateArrayFromList(« reason1, reason2 »).
- %cancelResult ~LET ~NOABRUPT `ReadableStreamCancel$A( %stream, %compositeReason ) ◎ Let cancelResult be ! ReadableStreamCancel(stream, compositeReason).
- `~promiseを解決する$( %cancelPromise, %cancelResult ) ◎ Resolve cancelPromise with cancelResult.
- ~RET %cancelPromise ◎ Return cancelPromise.
-
%cancel2Algorithm ~LET 所与の ( %reason ) に対し,次を走らす~algo: ◎ Let cancel2Algorithm be the following steps, taking a reason argument:
- %canceled2 ~SET ~T ◎ Set canceled2 to true.
- %reason2 ~SET %reason ◎ Set reason2 to reason.
-
~IF[ %canceled1 ~EQ ~T ]: ◎ If canceled1 is true,
- %compositeReason ~LET ~NOABRUPT `CreateArrayFromList$Ax( « %reason1, %reason2 » ) ◎ Let compositeReason be ! CreateArrayFromList(« reason1, reason2 »).
- %cancelResult ~LET ~NOABRUPT `ReadableStreamCancel$A( %stream, %compositeReason ) ◎ Let cancelResult be ! ReadableStreamCancel(stream, compositeReason).
- `~promiseを解決する$( %cancelPromise, %cancelResult ) ◎ Resolve cancelPromise with cancelResult.
- ~RET %cancelPromise ◎ Return cancelPromise.
- %startAlgorithm ~LET 次を走らす~algo ⇒ ~RET `undefined^jv ◎ Let startAlgorithm be an algorithm that returns undefined.
- %branch1 ~SET ~NOABRUPT `CreateReadableStream$A( %startAlgorithm, %pullAlgorithm, %cancel1Algorithm) ◎ Set branch1 to ! CreateReadableStream(startAlgorithm, pullAlgorithm, cancel1Algorithm).
- %branch2 ~SET ~NOABRUPT `CreateReadableStream$A( %startAlgorithm, %pullAlgorithm, %cancel2Algorithm) ◎ Set branch2 to ! CreateReadableStream(startAlgorithm, pullAlgorithm, cancel2Algorithm).
-
事由 %r による %reader.`closedPromise$rsR の`却下-時$には: ◎ Upon rejection of reader.[[closedPromise]] with reason r,
- ~NOABRUPT `ReadableStreamDefaultControllerError$A( %branch1.`controller$rS, %r ) ◎ Perform ! ReadableStreamDefaultControllerError(branch1.[[controller]], r).
- ~NOABRUPT `ReadableStreamDefaultControllerError$A( %branch2.`controller$rS, %r ) ◎ Perform ! ReadableStreamDefaultControllerError(branch2.[[controller]], r).
- ~IF[ %canceled1 ~EQ ~F ]~OR[ %canceled2 ~EQ ~F ] ⇒ `~promiseを解決する$( %cancelPromise, `undefined^jv ) ◎ If canceled1 is false or canceled2 is false, resolve cancelPromise with undefined.
- ~RET « %branch1, %branch1 » ◎ Return « branch1, branch2 ».
`ReadableByteStreamTee(stream)@A は、次の手続きを遂行する: ◎ ReadableByteStreamTee(stream) performs the following steps:
- ~Assert: %stream は `ReadableStream$I を`実装する$ ◎ Assert: stream implements ReadableStream.
- ~Assert: %stream.`controller$rS は `ReadableByteStreamController$I を`実装する$ ◎ Assert: stream.[[controller]] implements ReadableByteStreamController.
- %reader ~LET ~ABRUPT `AcquireReadableStreamDefaultReader$A( %stream ) ◎ Let reader be ? AcquireReadableStreamDefaultReader(stream).
- %reading ~LET ~F ◎ Let reading be false.
- %readAgainForBranch1 ~LET ~F ◎ Let readAgainForBranch1 be false.
- %readAgainForBranch2 ~LET ~F ◎ Let readAgainForBranch2 be false.
- %canceled1 ~LET ~F ◎ Let canceled1 be false.
- %canceled2 ~LET ~F ◎ Let canceled2 be false.
- %reason1 ~LET `undefined^jv ◎ Let reason1 be undefined.
- %reason2 ~LET `undefined^jv ◎ Let reason2 be undefined.
- %branch1 ~LET `undefined^jv ◎ Let branch1 be undefined.
- %branch2 ~LET `undefined^jv ◎ Let branch2 be undefined.
- %cancelPromise ~LET `新たな~promise$ ◎ Let cancelPromise be a new promise.
-
%forwardReaderError ~LET 所与の ( %thisReader ) に対し,次を走らす~algo: ◎ Let forwardReaderError be the following steps, taking a thisReader argument:
-
事由 %r による %thisReader.`closedPromise$rsR の`却下-時$には: ◎ Upon rejection of thisReader.[[closedPromise]] with reason r,
- ~IF[ %thisReader ~NEQ %reader ] ⇒ ~RET ◎ If thisReader is not reader, return.
- ~NOABRUPT `ReadableByteStreamControllerError$A( %branch1.`controller$rS, %r ) ◎ Perform ! ReadableByteStreamControllerError(branch1.[[controller]], r).
- ~NOABRUPT `ReadableByteStreamControllerError$A( %branch2.`controller$rS, %r ) ◎ Perform ! ReadableByteStreamControllerError(branch2.[[controller]], r).
- ~IF[ %canceled1 ~EQ ~F ]~OR[ %canceled2 ~EQ ~F ] ⇒ `~promiseを解決する$( %cancelPromise, `undefined^jv ) ◎ If canceled1 is false or canceled2 is false, resolve cancelPromise with undefined.
-
-
%pullWithDefaultReader ~LET 次を走らす~algo: ◎ Let pullWithDefaultReader be the following steps:
-
~IF[ %reader は `ReadableStreamBYOBReader$I を`実装する$ ]: ◎ If reader implements ReadableStreamBYOBReader,
- ~Assert: %reader.`readIntoRequests$rsR は`空$である ◎ Assert: reader.[[readIntoRequests]] is empty.
- ~NOABRUPT `ReadableStreamBYOBReaderRelease$A( %reader ) ◎ Perform ! ReadableStreamBYOBReaderRelease(reader).
- %reader ~SET ~NOABRUPT `AcquireReadableStreamDefaultReader$A( %stream ) ◎ Set reader to ! AcquireReadableStreamDefaultReader(stream).
- %forwardReaderError( %reader ) ◎ Perform forwardReaderError, given reader.
-
%readRequest ~LET 次に挙げる`~item$sctを伴う,新たな`読取n要請$: ◎ Let readRequest be a read request with the following items:
-
`~chunk手続き$rRは、 所与の ( %chunk ) に対し ⇒ `小taskを~queueする$( 次の手続き ) ◎ chunk steps, given chunk • Queue a microtask to perform\
手続きは: ◎ the following steps:
- %readAgainForBranch1 ~SET ~F ◎ Set readAgainForBranch1 to false.
- %readAgainForBranch2 ~SET ~F ◎ Set readAgainForBranch2 to false.
- %chunk1 ~LET %chunk ◎ ↓
- %chunk2 ~LET %chunk ◎ Let chunk1 and chunk2 be chunk.
-
~IF[ %canceled1 ~EQ ~F ]~AND[ %canceled2 ~EQ ~F ]: ◎ If canceled1 is false and canceled2 is false,
- %cloneResult ~LET `CloneAsUint8Array$A( %chunk ) ◎ Let cloneResult be CloneAsUint8Array(chunk).
-
~IF[ %cloneResult は`中途完了^である ]: ◎ If cloneResult is an abrupt completion,
- ~NOABRUPT `ReadableByteStreamControllerError$A( %branch1.`controller$rS, %cloneResult.`Value^sl ) ◎ Perform ! ReadableByteStreamControllerError(branch1.[[controller]], cloneResult.[[Value]]).
- ~NOABRUPT `ReadableByteStreamControllerError$A( %branch2.`controller$rS, %cloneResult.`Value^sl ) ◎ Perform ! ReadableByteStreamControllerError(branch2.[[controller]], cloneResult.[[Value]]).
- `~promiseを解決する$( %cancelPromise, 次の結果 ) ⇒ ~NOABRUPT `ReadableStreamCancel$A( %stream, %cloneResult.`Value^sl ) ◎ Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]).
- ~RET ◎ Return.
- ~ELSE ⇒ %chunk2 ~SET %cloneResult.`Value^sl ◎ Otherwise, set chunk2 to cloneResult.[[Value]].
- ~IF[ %canceled1 ~EQ ~F ] ⇒ ~NOABRUPT `ReadableByteStreamControllerEnqueue$A( %branch1.`controller$rS, %chunk1 ) ◎ If canceled1 is false, perform ! ReadableByteStreamControllerEnqueue(branch1.[[controller]], chunk1).
- ~IF[ %canceled2 ~EQ ~F ] ⇒ ~NOABRUPT `ReadableByteStreamControllerEnqueue$A( %branch2.`controller$rS, %chunk2 ) ◎ If canceled2 is false, perform ! ReadableByteStreamControllerEnqueue(branch2.[[controller]], chunk2).
- %reading ~SET ~F ◎ Set reading to false.
- ~IF[ %readAgainForBranch1 ~EQ ~T ] ⇒ %pull1Algorithm を遂行する ◎ If readAgainForBranch1 is true, perform pull1Algorithm.
- ~ELIF[ %readAgainForBranch2 ~EQ ~T ] ⇒ %pull2Algorithm を遂行する ◎ Otherwise, if readAgainForBranch2 is true, perform pull2Algorithm.
注記: ここでの小taskによる遅延は、 必要yである — 下にて %reader.`closedPromise$rsR を利用するとき、 少なくとも,~errorを検出する小taskがかかるので。 %stream における~errorは,両~分岐とも即時に~errorにすることが求まれるので、 非同期的に可用な~errorに先んじて,成功裡な読取nを同期的に可用にするわけにはいかない。 ◎ The microtask delay here is necessary because it takes at least a microtask to detect errors, when we use reader.[[closedPromise]] below. We want errors in stream to error both branches immediately, so we cannot let successful synchronously-available reads happen ahead of asynchronously-available errors.
-
`~close手続き$rRは: ◎ close steps
- %reading ~SET ~F ◎ Set reading to false.
- ~IF[ %canceled1 ~EQ ~F ] ⇒ ~NOABRUPT `ReadableByteStreamControllerClose$A( %branch1.`controller$rS ) ◎ If canceled1 is false, perform ! ReadableByteStreamControllerClose(branch1.[[controller]]).
- ~IF[ %canceled2 ~EQ ~F ] ⇒ ~NOABRUPT `ReadableByteStreamControllerClose$A( %branch2.`controller$rS ) ◎ If canceled2 is false, perform ! ReadableByteStreamControllerClose(branch2.[[controller]]).
- ~IF[ %branch1.`controller$rS.`pendingPullIntos$rbsC は`空$でない ] ⇒ ~NOABRUPT `ReadableByteStreamControllerRespond$A( %branch1.`controller$rS, 0 ) ◎ If branch1.[[controller]].[[pendingPullIntos]] is not empty, perform ! ReadableByteStreamControllerRespond(branch1.[[controller]], 0).
- ~IF[ %branch2.`controller$rS.`pendingPullIntos$rbsC は`空$でない ] ⇒ ~NOABRUPT `ReadableByteStreamControllerRespond$A( %branch2.`controller$rS, 0 ) ◎ If branch2.[[controller]].[[pendingPullIntos]] is not empty, perform ! ReadableByteStreamControllerRespond(branch2.[[controller]], 0).
- ~IF[ %canceled1 ~EQ ~F ]~OR[ %canceled2 ~EQ ~F ] ⇒ `~promiseを解決する$( %cancelPromise, `undefined^jv ) ◎ If canceled1 is false or canceled2 is false, resolve cancelPromise with undefined.
- `~error手続き$rRは ⇒ %reading ~SET ~F ◎ error steps • Set reading to false.
-
- ~NOABRUPT `ReadableStreamDefaultReaderRead$A( %reader, %readRequest ) ◎ Perform ! ReadableStreamDefaultReaderRead(reader, readRequest).
-
-
%pullWithBYOBReader ~LET 所与の ( %view, %forBranch2 ) に対し,次を走らす~algo: ◎ Let pullWithBYOBReader be the following steps, given view and forBranch2:
-
~IF[ %reader は `ReadableStreamDefaultReader$I を`実装する$ ]: ◎ If reader implements ReadableStreamDefaultReader,
- ~Assert: %reader.`readRequests$rsR は`空$である ◎ Assert: reader.[[readRequests]] is empty.
- ~NOABRUPT `ReadableStreamDefaultReaderRelease$A( %reader ) ◎ Perform ! ReadableStreamDefaultReaderRelease(reader).
- %reader ~SET ~NOABRUPT `AcquireReadableStreamBYOBReader$A( %stream ) ◎ Set reader to ! AcquireReadableStreamBYOBReader(stream).
- %forwardReaderError( %reader ) ◎ Perform forwardReaderError, given reader.
- %byobBranch ~LET %forBranch2 に応じて ⇒# ~T ならば %branch2 / ~F ならば %branch1 ◎ Let byobBranch be branch2 if forBranch2 is true, and branch1 otherwise.
- %otherBranch ~LET %forBranch2 に応じて ⇒# ~F ならば %branch2 / ~T ならば %branch1 ◎ Let otherBranch be branch2 if forBranch2 is false, and branch1 otherwise.
-
%readIntoRequest ~LET 次に挙げる`~item$sctを伴う,新たな`中へ読取る要請$: ◎ Let readIntoRequest be a read-into request with the following items:
-
`~chunk手続き$riRは、 所与の ( %chunk ) に対し ⇒ `小taskを~queueする$( 次の手続き ) ◎ chunk steps, given chunk • Queue a microtask to perform\
手続きは: ◎ the following steps:
- %readAgainForBranch1 ~SET ~F ◎ Set readAgainForBranch1 to false.
- %readAgainForBranch2 ~SET ~F ◎ Set readAgainForBranch2 to false.
- %byobCanceled ~LET %forBranch2 に応じて ⇒# ~T ならば %canceled2 / ~F ならば %canceled1 ◎ Let byobCanceled be canceled2 if forBranch2 is true, and canceled1 otherwise.
- %otherCanceled ~LET %forBranch2 に応じて ⇒# ~F ならば %canceled2 / ~T ならば %canceled1 ◎ Let otherCanceled be canceled2 if forBranch2 is false, and canceled1 otherwise.
-
~IF[ %otherCanceled ~EQ ~F ]: ◎ If otherCanceled is false,
- %cloneResult ~LET `CloneAsUint8Array$A( %chunk ) ◎ Let cloneResult be CloneAsUint8Array(chunk).
-
~IF[ %cloneResult は`中途完了^である ]: ◎ If cloneResult is an abrupt completion,
- ~NOABRUPT `ReadableByteStreamControllerError$A( %byobBranch.`controller$rS, %cloneResult.`Value^sl ) ◎ Perform ! ReadableByteStreamControllerError(byobBranch.[[controller]], cloneResult.[[Value]]).
- ~NOABRUPT `ReadableByteStreamControllerError$A( %otherBranch.`controller$rS, %cloneResult.`Value^sl ) ◎ Perform ! ReadableByteStreamControllerError(otherBranch.[[controller]], cloneResult.[[Value]]).
- `~promiseを解決する$( %cancelPromise, 次の結果 ) ⇒ ~NOABRUPT `ReadableStreamCancel$A( %stream, %cloneResult.`Value^sl ) ◎ Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]).
- ~RET ◎ Return.
- ~ELSE ⇒ %clonedChunk ~LET %cloneResult.`Value^sl ◎ Otherwise, let clonedChunk be cloneResult.[[Value]].
- ~IF[ %byobCanceled ~EQ ~F ] ⇒ ~NOABRUPT `ReadableByteStreamControllerRespondWithNewView$A( %byobBranch.`controller$rS, %chunk ) ◎ If byobCanceled is false, perform ! ReadableByteStreamControllerRespondWithNewView(byobBranch.[[controller]], chunk).
- ~NOABRUPT `ReadableByteStreamControllerEnqueue$A( %otherBranch.`controller$rS, %clonedChunk ) ◎ Perform ! ReadableByteStreamControllerEnqueue(otherBranch.[[controller]], clonedChunk).
- ~ELIF[ %byobCanceled ~EQ ~F ] ⇒ ~NOABRUPT `ReadableByteStreamControllerRespondWithNewView$A( %byobBranch.`controller$rS, %chunk ) ◎ Otherwise, if byobCanceled is false, perform ! ReadableByteStreamControllerRespondWithNewView(byobBranch.[[controller]], chunk).
- %reading ~SET ~F ◎ Set reading to false.
- ~IF[ %readAgainForBranch1 ~EQ ~T ] ⇒ %pull1Algorithm を遂行する ◎ If readAgainForBranch1 is true, perform pull1Algorithm.
- ~ELIF[ %readAgainForBranch2 ~EQ ~T ] ⇒ %pull2Algorithm を遂行する ◎ Otherwise, if readAgainForBranch2 is true, perform pull2Algorithm.
注記: ここでの小taskによる遅延は、 必要yである — 下にて %reader.`closedPromise$rsR を利用するとき、 少なくとも,~errorを検出する小taskがかかるので。 %stream における~errorは,両~分岐とも即時に~errorにすることが求まれるので、 非同期的に可用な~errorに先んじて,成功裡な読取nを同期的に可用にするわけにはいかない。 ◎ The microtask delay here is necessary because it takes at least a microtask to detect errors, when we use reader.[[closedPromise]] below. We want errors in stream to error both branches immediately, so we cannot let successful synchronously-available reads happen ahead of asynchronously-available errors.
-
`~close手続き$riRは、 所与の ( %chunk ) に対し: ◎ close steps, given chunk
- %reading ~SET ~F ◎ Set reading to false.
- %byobCanceled ~LET %forBranch2 に応じて ⇒# ~T ならば %canceled2 / ~F ならば %canceled1 ◎ Let byobCanceled be canceled2 if forBranch2 is true, and canceled1 otherwise.
- %otherCanceled ~LET %forBranch2 に応じて ⇒# ~F ならば %canceled2 / ~T ならば %canceled1 ◎ Let otherCanceled be canceled2 if forBranch2 is false, and canceled1 otherwise.
- ~IF[ %byobCanceled ~EQ ~F ] ⇒ ~NOABRUPT `ReadableByteStreamControllerClose$A( %byobBranch.`controller$rS ) ◎ If byobCanceled is false, perform ! ReadableByteStreamControllerClose(byobBranch.[[controller]]).
- ~IF[ %otherCanceled ~EQ ~F ] ⇒ ~NOABRUPT `ReadableByteStreamControllerClose$A( %otherBranch.`controller$rS ) ◎ If otherCanceled is false, perform ! ReadableByteStreamControllerClose(otherBranch.[[controller]]).
-
~IF[ %chunk ~NEQ `undefined^jv ]: ◎ If chunk is not undefined,
- ~Assert: %chunk.`ByteLength^sl ~EQ 0 ◎ Assert: chunk.[[ByteLength]] is 0.
- ~IF[ %byobCanceled ~EQ ~F ] ⇒ ~NOABRUPT `ReadableByteStreamControllerRespondWithNewView$A( %byobBranch.`controller$rS, %chunk ) ◎ If byobCanceled is false, perform ! ReadableByteStreamControllerRespondWithNewView(byobBranch.[[controller]], chunk).
- ~IF[ %otherCanceled ~EQ ~F ]~AND[ %otherBranch.`controller$rS.`pendingPullIntos$rbsC は`空$でない ] ⇒ ~NOABRUPT `ReadableByteStreamControllerRespond$A( %otherBranch.`controller$rS, 0 ) ◎ If otherCanceled is false and otherBranch.[[controller]].[[pendingPullIntos]] is not empty, perform ! ReadableByteStreamControllerRespond(otherBranch.[[controller]], 0).
- ~IF[ %byobCanceled ~EQ ~F ]~OR[ %otherCanceled ~EQ ~F ] ⇒ `~promiseを解決する$( %cancelPromise, `undefined^jv ) ◎ If byobCanceled is false or otherCanceled is false, resolve cancelPromise with undefined.
-
`~error手続き$riRは ⇒ %reading ~SET ~F ◎ error steps • Set reading to false.
-
- ~NOABRUPT `ReadableStreamBYOBReaderRead$A( %reader, %view, 1, %readIntoRequest ) ◎ Perform ! ReadableStreamBYOBReaderRead(reader, view, 1, readIntoRequest).
-
-
%pull1Algorithm ~LET 次を走らす~algo: ◎ Let pull1Algorithm be the following steps:
-
~IF[ %reading ~EQ ~T ]: ◎ If reading is true,
- %readAgainForBranch1 ~SET ~T ◎ Set readAgainForBranch1 to true.
- ~RET `解決される~promise$( `undefined^jv ) ◎ Return a promise resolved with undefined.
- %reading ~SET ~T ◎ Set reading to true.
- %byobRequest ~LET ~NOABRUPT `ReadableByteStreamControllerGetBYOBRequest$A( %branch1.`controller$rS ) ◎ Let byobRequest be ! ReadableByteStreamControllerGetBYOBRequest(branch1.[[controller]]).
- ~IF[ %byobRequest ~EQ ~NULL ] ⇒ %pullWithDefaultReader() ◎ If byobRequest is null, perform pullWithDefaultReader.
- ~ELSE ⇒ %pullWithBYOBReader( %byobRequest.`view$bbrQ, ~F ) ◎ Otherwise, perform pullWithBYOBReader, given byobRequest.[[view]] and false.
- ~RET `解決される~promise$( `undefined^jv ) ◎ Return a promise resolved with undefined.
-
-
%pull2Algorithm ~LET 次を走らす~algo: ◎ Let pull2Algorithm be the following steps:
-
~IF[ %reading ~EQ ~T ]: ◎ If reading is true,
- %readAgainForBranch2 ~SET ~T ◎ Set readAgainForBranch2 to true.
- ~RET `解決される~promise$( `undefined^jv ) ◎ Return a promise resolved with undefined.
- %reading ~SET ~T ◎ Set reading to true.
- %byobRequest ~LET ~NOABRUPT `ReadableByteStreamControllerGetBYOBRequest$A( %branch2.`controller$rS ) ◎ Let byobRequest be ! ReadableByteStreamControllerGetBYOBRequest(branch2.[[controller]]).
- ~IF[ %byobRequest ~EQ ~NULL ] ⇒ %pullWithDefaultReader() ◎ If byobRequest is null, perform pullWithDefaultReader.
- ~ELSE ⇒ %pullWithBYOBReader( %byobRequest.`view$bbrQ, ~T ) ◎ Otherwise, perform pullWithBYOBReader, given byobRequest.[[view]] and true.
- ~RET `解決される~promise$( `undefined^jv ) ◎ Return a promise resolved with undefined.
-
-
%cancel1Algorithm ~LET 所与の ( %reason ) に対し,次を走らす~algo: ◎ Let cancel1Algorithm be the following steps, taking a reason argument:
- %canceled1 ~SET ~T ◎ Set canceled1 to true.
- %reason1 ~SET %reason ◎ Set reason1 to reason.
-
~IF[ %canceled2 ~EQ ~T ]: ◎ If canceled2 is true,
- %compositeReason ~LET ~NOABRUPT `CreateArrayFromList$Ax ( « %reason1, %reason2 » ) ◎ Let compositeReason be ! CreateArrayFromList(« reason1, reason2 »).
- %cancelResult ~LET ~NOABRUPT `ReadableStreamCancel$A( %stream, %compositeReason ) ◎ Let cancelResult be ! ReadableStreamCancel(stream, compositeReason).
- `~promiseを解決する$( %cancelPromise, %cancelResult ) ◎ Resolve cancelPromise with cancelResult.
- ~RET %cancelPromise ◎ Return cancelPromise.
-
%cancel2Algorithm ~LET 所与の ( %reason ) に対し,次を走らす~algo: ◎ Let cancel2Algorithm be the following steps, taking a reason argument:
- %canceled2 ~SET ~T ◎ Set canceled2 to true.
- %reason2 ~SET %reason ◎ Set reason2 to reason.
-
~IF[ %canceled1 ~EQ ~T ]: ◎ If canceled1 is true,
- %compositeReason ~LET ~NOABRUPT `CreateArrayFromList$Ax ( « %reason1, %reason2 » ) ◎ Let compositeReason be ! CreateArrayFromList(« reason1, reason2 »).
- %cancelResult ~LET ~NOABRUPT `ReadableStreamCancel$A( %stream, %compositeReason ) ◎ Let cancelResult be ! ReadableStreamCancel(stream, compositeReason).
- `~promiseを解決する$( %cancelPromise, %cancelResult ) ◎ Resolve cancelPromise with cancelResult.
- ~RET %cancelPromise ◎ Return cancelPromise.
- %startAlgorithm ~LET 次を走らす~algo ⇒ ~RET `undefined^jv ◎ Let startAlgorithm be an algorithm that returns undefined.
- %branch1 ~SET ~NOABRUPT `CreateReadableByteStream$A( %startAlgorithm, %pull1Algorithm, %cancel1Algorithm ) ◎ Set branch1 to ! CreateReadableByteStream(startAlgorithm, pull1Algorithm, cancel1Algorithm).
- %branch2 ~SET ~NOABRUPT `CreateReadableByteStream$A( %startAlgorithm, %pull2Algorithm, %cancel2Algorithm ) ◎ Set branch2 to ! CreateReadableByteStream(startAlgorithm, pull2Algorithm, cancel2Algorithm).
- %forwardReaderError( %reader ) ◎ Perform forwardReaderError, given reader.
- ~RET « %branch1, %branch2 » ◎ Return « branch1, branch2 ».
4.9.2. 制御器との~interface法
仕様の~~構成においては、 多様になり得る~logicを成す大部分を 2 種の制御器~class[ `ReadableStreamDefaultController$I, `ReadableByteStreamController$I ]の内側に集中させることにより、 単純な[ `可読~stream$, `可読~byte~stream$ ]両者の挙動が,単独の `ReadableStream$I ~classの中に~capsule化されている。 これらの制御器~classは、[ ~streamの`内部~queue$を管理する方法, および ~streamの[ `下層~source$/`下層~byte~source$ ]と~interfaceするための[ ~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は、 3 つの内部~methodを定義する — それらは、 `ReadableStream$I の各種~algoから~callされる: ◎ Each controller class defines three internal methods, which are called by the ReadableStream algorithms:
- `CancelSteps@sl(%reason)
- ~streamが`取消され$たときの反応として走らす,制御器の手続き。 制御器に格納されている状態を片付けて,`下層~source$に伝えるために利用される。 ◎ 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@sl(%readRequest)
- `既定の読取器$から読取られるときに走らす,制御器の手続き。 [ ~queue済みな`~chunk$を制御器から~pullする / もっと~chunkを取得するため`下層~source$から~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.
- `ReleaseSteps@sl()
- `読取器$が`解放-$されたときに走らす,制御器の手続き — 制御器~内に格納された[ 読取器に特有な資源 ]を片付けるために利用される。 ◎ The controller’s steps that run when a reader is released, used to clean up reader-specific resources stored in the controller.
(これらは、 制御器の型に応じて分岐させることなく, 各種 `ReadableStream$I ~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$I ~objに影響させる ]ために利用される。 これは、 制御器における内部~状態~変化を[ `ReadableStream$I の公な~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.
`ReadableStreamAddReadIntoRequest(stream, readRequest)@A は、次の手続きを遂行する: ◎ ReadableStreamAddReadIntoRequest(stream, readRequest) performs the following steps:
- ~Assert: %stream.`reader$rS は `ReadableStreamBYOBReader$I を`実装する$ ◎ Assert: stream.[[reader]] implements ReadableStreamBYOBReader.
- ~Assert: %stream.`state$rS ~IN { `readable^l, `closed^l } ◎ Assert: stream.[[state]] is "readable" or "closed".
- %stream.`reader$rS.`readIntoRequests$rsR に %readRequest を`付加する$ ◎ Append readRequest to stream.[[reader]].[[readIntoRequests]].
`ReadableStreamAddReadRequest(stream, readRequest)@A は、次の手続きを遂行する: ◎ ReadableStreamAddReadRequest(stream, readRequest performs the following steps:
- ~Assert: %stream.`reader$rS は `ReadableStreamDefaultReader$I を`実装する$ ◎ Assert: stream.[[reader]] implements ReadableStreamDefaultReader.
- ~Assert: %stream.`state$rS ~EQ `readable^l ◎ Assert: stream.[[state]] is "readable".
- %stream.`reader$rS.`readRequests$rsR に %readRequest を`付加する$ ◎ Append readRequest to stream.[[reader]].[[readRequests]].
`ReadableStreamCancel(stream, reason)@A は、次の手続きを遂行する: ◎ ReadableStreamCancel(stream, reason) performs the following steps:
- %stream.`disturbed$rS ~SET ~T ◎ Set stream.[[disturbed]] to true.
- ~IF[ %stream.`state$rS ~EQ `closed^l ] ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ If stream.[[state]] is "closed", return a promise resolved with undefined.
- ~IF[ %stream.`state$rS ~EQ `errored^l ] ⇒ ~RET `却下される~promise$( %stream.`storedError$rS ) ◎ If stream.[[state]] is "errored", return a promise rejected with stream.[[storedError]].
- ~NOABRUPT `ReadableStreamClose$A( %stream ) ◎ Perform ! ReadableStreamClose(stream).
- %reader ~LET %stream.`reader$rS ◎ Let reader be stream.[[reader]].
-
~IF[ %reader ~NEQ `undefined^jv ]~AND[ %reader は `ReadableStreamBYOBReader$I を`実装する$ ]: ◎ If reader is not undefined and reader implements ReadableStreamBYOBReader,
- %readIntoRequests ~LET %reader.`readIntoRequests$rsR ◎ Let readIntoRequests be reader.[[readIntoRequests]].
- %reader.`readIntoRequests$rsR ~SET 空`~list$ ◎ Set reader.[[readIntoRequests]] to an empty list.
- %readIntoRequests を成す ~EACH( %readIntoRequest ) に対し ⇒ %readIntoRequest の`~close手続き$riR( `undefined^jv ) ◎ For each readIntoRequest of readIntoRequests, • Perform readIntoRequest’s close steps, given undefined.
- %sourceCancelPromise ~LET ~NOABRUPT %stream.`controller$rS.`CancelSteps$sl( %reason ) ◎ Let sourceCancelPromise be ! stream.[[controller]].[[CancelSteps]](reason).
-
~RET `~promiseに反応する$( %sourceCancelPromise ) — 次を与える下で:
- `充足~手続き^i は ⇒ ~RET `undefined^jv
`ReadableStreamClose(stream)@A は、次の手続きを遂行する: ◎ ReadableStreamClose(stream) performs the following steps:
- ~Assert: %stream.`state$rS ~EQ `readable^l ◎ Assert: stream.[[state]] is "readable".
- %stream.`state$rS ~SET `closed^l ◎ Set stream.[[state]] to "closed".
- %reader ~LET %stream.`reader$rS ◎ Let reader be stream.[[reader]].
- ~IF[ %reader ~EQ `undefined^jv ] ⇒ ~RET ◎ If reader is undefined, return.
- `~promiseを解決する$( %reader.`closedPromise$rsR, `undefined^jv ) ◎ Resolve reader.[[closedPromise]] with undefined.
-
~IF[ %reader は `ReadableStreamDefaultReader$I を`実装する$ ]: ◎ If reader implements ReadableStreamDefaultReader,
- %readRequests ~LET %reader.`readRequests$rsR ◎ Let readRequests be reader.[[readRequests]].
- %reader.`readRequests$rsR ~SET 空`~list$ ◎ Set reader.[[readRequests]] to an empty list.
- %readRequests を成す ~EACH( %readRequest ) に対し ⇒ %readRequest の`~close手続き$rR() ◎ For each readRequest of readRequests, • Perform readRequest’s close steps.
`ReadableStreamError(stream, e)@A は、次の手続きを遂行する: ◎ ReadableStreamError(stream, e) performs the following steps:
- ~Assert: %stream.`state$rS ~EQ `readable^l ◎ Assert: stream.[[state]] is "readable".
- %stream.`state$rS ~SET `errored^l ◎ Set stream.[[state]] to "errored".
- %stream.`storedError$rS ~SET %e ◎ Set stream.[[storedError]] to e.
- %reader ~LET %stream.`reader$rS ◎ Let reader be stream.[[reader]].
- ~IF[ %reader ~EQ `undefined^jv ] ⇒ ~RET ◎ If reader is undefined, return.
- `~promiseを却下する$( %reader.`closedPromise$rsR, %e ) ◎ Reject reader.[[closedPromise]] with e.
- %reader.`closedPromise$rsR.`PromiseIsHandled^sl ~SET ~T ◎ Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
-
~IF[ %reader は `ReadableStreamDefaultReader$I を`実装する$ ] ⇒ ~NOABRUPT `ReadableStreamDefaultReaderErrorReadRequests$A( %reader, %e ) ◎ If reader implements ReadableStreamDefaultReader, • Perform ! ReadableStreamDefaultReaderErrorReadRequests(reader, e).
-
~ELSE: ◎ Otherwise,
- ~Assert: %reader は `ReadableStreamBYOBReader$I を`実装する$ ◎ Assert: reader implements ReadableStreamBYOBReader.
- ~NOABRUPT `ReadableStreamBYOBReaderErrorReadIntoRequests$A( %reader, %e ) ◎ Perform ! ReadableStreamBYOBReaderErrorReadIntoRequests(reader, e).
`ReadableStreamFulfillReadIntoRequest(stream, chunk, done)@A は、次の手続きを遂行する: ◎ ReadableStreamFulfillReadIntoRequest(stream, chunk, done) performs the following steps:
- ~Assert: ~NOABRUPT `ReadableStreamHasBYOBReader$A( %stream ) ~EQ ~T ◎ Assert: ! ReadableStreamHasBYOBReader(stream) is true.
- %reader ~LET %stream.`reader$rS ◎ Let reader be stream.[[reader]].
- ~Assert: %reader.`readIntoRequests$rsR は`空$でない ◎ Assert: reader.[[readIntoRequests]] is not empty.
- %readIntoRequest ~LET %reader.`readIntoRequests$rsR[0] ◎ Let readIntoRequest be reader.[[readIntoRequests]][0].
- %reader.`readIntoRequests$rsR から %readIntoRequest を`除去する$ ◎ Remove readIntoRequest from reader.[[readIntoRequests]].
- ~IF[ %done ~EQ ~T ] ⇒ %readIntoRequest の`~close手続き$riR( %chunk ) ◎ If done is true, perform readIntoRequest’s close steps, given chunk.
- ~ELSE ⇒ %readIntoRequest の`~chunk手続き$riR( %chunk ) ◎ Otherwise, perform readIntoRequest’s chunk steps, given chunk.
`ReadableStreamFulfillReadRequest(stream, chunk, done)@A は、次の手続きを遂行する: ◎ ReadableStreamFulfillReadRequest(stream, chunk, done) performs the following steps:
- ~Assert: ~NOABRUPT `ReadableStreamHasDefaultReader$A( %stream ) ~EQ ~T ◎ Assert: ! ReadableStreamHasDefaultReader(stream) is true.
- %reader ~LET %stream.`reader$rS ◎ Let reader be stream.[[reader]].
- ~Assert: %reader.`readRequests$rsR は`空$でない ◎ Assert: reader.[[readRequests]] is not empty.
- %readRequest ~LET %reader.`readRequests$rsR[0] ◎ Let readRequest be reader.[[readRequests]][0].
- %reader.`readRequests$rsR から %readRequest を`除去する$ ◎ Remove readRequest from reader.[[readRequests]].
- ~IF[ %done ~EQ ~T ] ⇒ %readRequest の`~close手続き$rR() ◎ If done is true, perform readRequest’s close steps.
- ~ELSE ⇒ %readRequest の`~chunk手続き$rR( %chunk ) ◎ Otherwise, perform readRequest’s chunk steps, given chunk.
`ReadableStreamGetNumReadIntoRequests(stream)@A は、次の手続きを遂行する: ◎ ReadableStreamGetNumReadIntoRequests(stream) performs the following steps:
- ~Assert: ~NOABRUPT `ReadableStreamHasBYOBReader$A( %stream ) ~EQ ~T ◎ Assert: ! ReadableStreamHasBYOBReader(stream) is true.
- ~RET %stream.`reader$rS.`readIntoRequests$rsR の`~size$ ◎ Return stream.[[reader]].[[readIntoRequests]]'s size.
`ReadableStreamGetNumReadRequests(stream)@A は、次の手続きを遂行する: ◎ ReadableStreamGetNumReadRequests(stream) performs the following steps:
- ~Assert: ~NOABRUPT `ReadableStreamHasDefaultReader$A( %stream ) ~EQ ~T ◎ Assert: ! ReadableStreamHasDefaultReader(stream) is true.
- ~RET %stream.`reader$rS.`readRequests$rsR の`~size$ ◎ Return stream.[[reader]].[[readRequests]]'s size.
`ReadableStreamHasBYOBReader(stream)@A は、次の手続きを遂行する: ◎ ReadableStreamHasBYOBReader(stream) performs the following steps:
- %reader ~LET %stream.`reader$rS ◎ Let reader be stream.[[reader]].
- ~IF[ %reader ~EQ `undefined^jv ] ⇒ ~RET ~F ◎ If reader is undefined, return false.
- ~IF[ %reader は `ReadableStreamBYOBReader$I を`実装する$ ] ⇒ ~RET ~T ◎ If reader implements ReadableStreamBYOBReader, return true.
- ~RET ~F ◎ Return false.
`ReadableStreamHasDefaultReader(stream)@A は、次の手続きを遂行する: ◎ ReadableStreamHasDefaultReader(stream) performs the following steps:
- %reader ~LET %stream.`reader$rS ◎ Let reader be stream.[[reader]].
- ~IF[ %reader ~EQ `undefined^jv ] ⇒ ~RET ~F ◎ If reader is undefined, return false.
- ~IF[ %reader は `ReadableStreamDefaultReader$I を`実装する$ ] ⇒ ~RET ~T ◎ If reader implements ReadableStreamDefaultReader, return true.
- ~RET ~F ◎ Return false.
4.9.3. 読取器
以下に与える抽象-演算は、[ `ReadableStreamDefaultReader$I / `ReadableStreamBYOBReader$I ]~instanceの実装と操作を~supportする。 ◎ The following abstract operations support the implementation and manipulation of ReadableStreamDefaultReader and ReadableStreamBYOBReader instances.
`ReadableStreamReaderGenericCancel(reader, reason)@A は、次の手続きを遂行する: ◎ ReadableStreamReaderGenericCancel(reader, reason) performs the following steps:
- %stream ~LET %reader.`stream$rsR ◎ Let stream be reader.[[stream]].
- ~Assert: %stream ~NEQ `undefined^jv ◎ Assert: stream is not undefined.
- ~RET ~NOABRUPT `ReadableStreamCancel$A( %stream, %reason ) ◎ Return ! ReadableStreamCancel(stream, reason).
`ReadableStreamReaderGenericInitialize(reader, stream)@A は、次の手続きを遂行する: ◎ ReadableStreamReaderGenericInitialize(reader, stream) performs the following steps:
- %reader.`stream$rsR ~SET %stream ◎ Set reader.[[stream]] to stream.
- %stream.`reader$rS ~SET %reader ◎ Set stream.[[reader]] to reader.
-
~IF[ %stream.`state$rS ~EQ `readable^l ]: ◎ If stream.[[state]] is "readable",
- %reader.`closedPromise$rsR ~SET `新たな~promise$ ◎ Set reader.[[closedPromise]] to a new promise.
-
~ELIF[ %stream.`state$rS ~EQ `closed^l ]: ◎ Otherwise, if stream.[[state]] is "closed",
- %reader.`closedPromise$rsR ~SET `解決される~promise$( `undefined^jv ) ◎ Set reader.[[closedPromise]] to a promise resolved with undefined.
-
~ELSE: ◎ Otherwise,
- ~Assert: %stream.`state$rS ~EQ `errored^l ◎ Assert: stream.[[state]] is "errored".
- %reader.`closedPromise$rsR ~SET `却下される~promise$( %stream.`storedError$rS ) ◎ Set reader.[[closedPromise]] to a promise rejected with stream.[[storedError]].
- %reader.`closedPromise$rsR.`PromiseIsHandled^sl ~SET ~T ◎ Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
`ReadableStreamReaderGenericRelease(reader)@A は、次の手続きを遂行する: ◎ ReadableStreamReaderGenericRelease(reader) performs the following steps:
- %stream ~LET %reader.`stream$rsR ◎ Let stream be reader.[[stream]].
- ~Assert: %stream ~NEQ `undefined^jv ◎ Assert: stream is not undefined.
- ~Assert: %stream.`reader$rS ~EQ %reader ◎ Assert: stream.[[reader]] is reader.
- ~IF[ %stream.`state$rS ~EQ `readable^l ] ⇒ `~promiseを却下する$( %reader.`closedPromise$rsR, `TypeError$jE ) ◎ If stream.[[state]] is "readable", reject reader.[[closedPromise]] with a TypeError exception.
- ~ELSE ⇒ %reader.`closedPromise$rsR ~SET `却下される~promise$( `TypeError$jE 例外 ) ◎ Otherwise, set reader.[[closedPromise]] to a promise rejected with a TypeError exception.
- %reader.`closedPromise$rsR.`PromiseIsHandled^sl ~SET ~T ◎ Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
- ~NOABRUPT %stream.`controller$rS.`ReleaseSteps$sl ◎ Perform ! stream.[[controller]].[[ReleaseSteps]]().
- %stream.`reader$rS ~SET `undefined^jv ◎ Set stream.[[reader]] to undefined.
- %stream.`stream$rsR ~SET `undefined^jv ◎ Set reader.[[stream]] to undefined.
`ReadableStreamBYOBReaderErrorReadIntoRequests(reader, e)@A は、次の手続きを遂行する: ◎ ReadableStreamBYOBReaderErrorReadIntoRequests(reader, e) performs the following steps:
- %readIntoRequests ~LET %reader.`readIntoRequests$rsR ◎ Let readIntoRequests be reader.[[readIntoRequests]].
- %reader.`readIntoRequests$rsR ~SET 新たな空`~list$ ◎ Set reader.[[readIntoRequests]] to a new empty list.
- %readIntoRequests を成す ~EACH( %readIntoRequest ) に対し ⇒ %readIntoRequest の`~error手続き$riR( %e ) ◎ For each readIntoRequest of readIntoRequests, • Perform readIntoRequest’s error steps, given e.
`ReadableStreamBYOBReaderRead(reader, view, min, readIntoRequest)@A は、次の手続きを遂行する: ◎ ReadableStreamBYOBReaderRead(reader, view, min, readIntoRequest) performs the following steps:
- %stream ~LET %reader.`stream$rsR ◎ Let stream be reader.[[stream]].
- ~Assert: %stream ~NEQ `undefined^jv ◎ Assert: stream is not undefined.
- %stream.`disturbed$rS ~SET ~T ◎ Set stream.[[disturbed]] to true.
- ~IF[ %stream.`state$rS ~EQ `errored^l ] ⇒ %readIntoRequest の`~error手続き$riR( %stream.`storedError$rS ) ◎ If stream.[[state]] is "errored", perform readIntoRequest’s error steps given stream.[[storedError]].
- ~ELSE ⇒ ~NOABRUPT `ReadableByteStreamControllerPullInto$A( %stream.`controller$rS, %view, %min, %readIntoRequest ) ◎ Otherwise, perform ! ReadableByteStreamControllerPullInto(stream.[[controller]], view, min, readIntoRequest).
`ReadableStreamBYOBReaderRelease(reader)@A は、次の手続きを遂行する: ◎ ReadableStreamBYOBReaderRelease(reader) performs the following steps:
- ~NOABRUPT `ReadableStreamReaderGenericRelease$A( %reader ) ◎ Perform ! ReadableStreamReaderGenericRelease(reader).
- %e ~LET 新たな `TypeError$jE 例外 ◎ Let e be a new TypeError exception.
- ~NOABRUPT `ReadableStreamBYOBReaderErrorReadIntoRequests$A( %reader, %e ) ◎ Perform ! ReadableStreamBYOBReaderErrorReadIntoRequests(reader, e).
`ReadableStreamDefaultReaderErrorReadRequests(reader, e)@A は、次の手続きを遂行する: ◎ ReadableStreamDefaultReaderErrorReadRequests(reader, e) performs the following steps:
- %readRequests ~LET %reader.`readRequests$rsR ◎ Let readRequests be reader.[[readRequests]].
- %reader.`readRequests$rsR ~SET 新たな空`~list$ ◎ Set reader.[[readRequests]] to a new empty list.
- %readRequests を成す ~EACH( %readRequest ) に対し ⇒ %readRequest の`~error手続き$rR( %e ) ◎ For each readRequest of readRequests, • Perform readRequest’s error steps, given e.
`ReadableStreamDefaultReaderRead(reader, readRequest)@A は、次の手続きを遂行する: ◎ ReadableStreamDefaultReaderRead(reader, readRequest) performs the following steps:
- %stream ~LET %reader.`stream$rsR ◎ Let stream be reader.[[stream]].
- ~Assert: %stream ~NEQ `undefined^jv ◎ Assert: stream is not undefined.
- %stream.`disturbed$rS ~SET ~T ◎ Set stream.[[disturbed]] to true.
- ~IF[ %stream.`state$rS ~EQ `closed^l ] ⇒ %readRequest の`~close手続き$rR() ◎ If stream.[[state]] is "closed", perform readRequest’s close steps.
- ~ELIF[ %stream.`state$rS ~EQ `errored^l ] ⇒ %readRequest の`~error手続き$rR( %stream.`storedError$rS ) ◎ Otherwise, if stream.[[state]] is "errored", perform readRequest’s error steps given stream.[[storedError]].
-
~ELSE: ◎ Otherwise,
- ~Assert: %stream.`state$rS ~EQ `readable^l ◎ Assert: stream.[[state]] is "readable".
- ~NOABRUPT %stream.`controller$rS.`PullSteps$sl( %readRequest ) ◎ Perform ! stream.[[controller]].[[PullSteps]](readRequest).
`ReadableStreamDefaultReaderRelease(reader)@A は、次の手続きを遂行する: ◎ ReadableStreamDefaultReaderRelease(reader) performs the following steps:
- ~NOABRUPT `ReadableStreamReaderGenericRelease$A( %reader ) ◎ Perform ! ReadableStreamReaderGenericRelease(reader).
- %e ~LET 新たな `TypeError$jE 例外 ◎ Let e be a new TypeError exception.
- ~NOABRUPT `ReadableStreamDefaultReaderErrorReadRequests$A( %reader, %e ) ◎ Perform ! ReadableStreamDefaultReaderErrorReadRequests(reader, e).
`SetUpReadableStreamBYOBReader(reader, stream)@A は、次の手続きを遂行する: ◎ SetUpReadableStreamBYOBReader(reader, stream) performs the following steps:
- ~IF[ ~NOABRUPT `IsReadableStreamLocked$A( %stream ) ~EQ ~T ] ⇒ ~THROW `TypeError$jE ◎ If ! IsReadableStreamLocked(stream) is true, throw a TypeError exception.
- ~IF[ %stream.`controller$rS は `ReadableByteStreamController$I を`実装しない$ ] ⇒ ~THROW `TypeError$jE ◎ If stream.[[controller]] does not implement ReadableByteStreamController, throw a TypeError exception.
- ~NOABRUPT `ReadableStreamReaderGenericInitialize$A( %reader, %stream ) ◎ Perform ! ReadableStreamReaderGenericInitialize(reader, stream).
- %reader.`readIntoRequests$rsR ~SET 新たな空`~list$ ◎ Set reader.[[readIntoRequests]] to a new empty list.
`SetUpReadableStreamDefaultReader(reader, stream)@A は、次の手続きを遂行する: ◎ SetUpReadableStreamDefaultReader(reader, stream) performs the following steps:
- ~IF[ ~NOABRUPT `IsReadableStreamLocked$A( %stream ) ~EQ ~T ] ⇒ ~THROW `TypeError$jE ◎ If ! IsReadableStreamLocked(stream) is true, throw a TypeError exception.
- ~NOABRUPT `ReadableStreamReaderGenericInitialize$A( %reader, %stream ) ◎ Perform ! ReadableStreamReaderGenericInitialize(reader, stream).
- %reader.`readRequests$rsR ~SET 新たな空`~list$ ◎ Set reader.[[readRequests]] to a new empty list.
4.9.4. 既定の制御器
以下に与える抽象-演算は、 `ReadableStreamDefaultController$I ~classの実装を~supportする。 ◎ The following abstract operations support the implementation of the ReadableStreamDefaultController class.
`ReadableStreamDefaultControllerCallPullIfNeeded(controller)@A は、次の手続きを遂行する: ◎ ReadableStreamDefaultControllerCallPullIfNeeded(controller) performs the following steps:
- %shouldPull ~LET ~NOABRUPT `ReadableStreamDefaultControllerShouldCallPull$A( %controller ) ◎ Let shouldPull be ! ReadableStreamDefaultControllerShouldCallPull(controller).
- ~IF[ %shouldPull ~EQ ~F ] ⇒ ~RET ◎ If shouldPull is false, return.
-
~IF[ %controller.`pulling$rsdC ~EQ ~T ]: ◎ If controller.[[pulling]] is true,
- %controller.`pullAgain$rsdC ~SET ~T ◎ Set controller.[[pullAgain]] to true.
- ~RET ◎ Return.
- ~Assert: %controller .`pullAgain$rsdC ~EQ ~F ◎ Assert: controller.[[pullAgain]] is false.
- %controller.`pulling$rsdC ~SET ~T ◎ Set controller.[[pulling]] to true.
-
%pullPromise ~LET %controller.`pullAlgorithm$rsdC() ◎ Let pullPromise be the result of performing controller.[[pullAlgorithm]].
-
%pullPromise の`充足-時$には: ◎ Upon fulfillment of pullPromise,
- %controller.`pulling$rsdC ~SET ~F ◎ Set controller.[[pulling]] to false.
-
~IF[ %controller.`pullAgain$rsdC ~EQ ~T ]: ◎ If controller.[[pullAgain]] is true,
- %controller.`pullAgain$rsdC ~SET ~F ◎ Set controller.[[pullAgain]] to false.
- ~NOABRUPT `ReadableStreamDefaultControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(controller).
-
事由 %e による %pullPromise の`却下-時$には: ◎ Upon rejection of pullPromise with reason e,
- ~NOABRUPT `ReadableStreamDefaultControllerError$A( %controller, %e ) ◎ Perform ! ReadableStreamDefaultControllerError(controller, e).
-
`ReadableStreamDefaultControllerShouldCallPull(controller)@A は、次の手続きを遂行する: ◎ ReadableStreamDefaultControllerShouldCallPull(controller) performs the following steps:
- %stream ~LET %controller.`stream$rsdC ◎ Let stream be controller.[[stream]].
- ~IF[ ~NOABRUPT `ReadableStreamDefaultControllerCanCloseOrEnqueue$A( %controller ) ~EQ ~F ] ⇒ ~RET ~F ◎ If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) is false, return false.
- ~IF[ %controller.`started$rsdC ~EQ ~F ] ⇒ ~RET ~F ◎ If controller.[[started]] is false, return false.
- ~IF[ ~NOABRUPT `IsReadableStreamLocked$A( %stream ) ~EQ ~T ]~AND[ ~NOABRUPT `ReadableStreamGetNumReadRequests$A( %stream ) ~GT 0 ] ⇒ ~RET ~T ◎ If ! IsReadableStreamLocked(stream) is true and ! ReadableStreamGetNumReadRequests(stream) > 0, return true.
- %desiredSize ~LET ~NOABRUPT `ReadableStreamDefaultControllerGetDesiredSize$A( %controller ) ◎ Let desiredSize be ! ReadableStreamDefaultControllerGetDesiredSize(controller).
- ~Assert: %desiredSize ~NEQ ~NULL ◎ Assert: desiredSize is not null.
- ~IF[ %desiredSize ~GT 0 ] ⇒ ~RET ~T ◎ If desiredSize > 0, return true.
- ~RET ~F ◎ Return false.
`ReadableStreamDefaultControllerClearAlgorithms(controller)@A は、[ ~streamが~closeされるか~errorして, 各種~algoが それ以上~実行されなくなったとき ]に~callされる。 これは、 各種~algoへの参照を除去することにより, `下層~source$( `ReadableStream$I ~obj)自身が — まだ参照されていても — ~garbage収集されることを許可する。 ◎ ReadableStreamDefaultControllerClearAlgorithms(controller) 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 source object to be garbage collected even if the ReadableStream itself is still referenced.
注記: これは、 `弱い参照@https://github.com/tc39/proposal-weakrefs/$を利用すれば観測-可能になる。 詳細は `tc39/proposal-weakrefs#31@https://github.com/tc39/proposal-weakrefs/issues/31$ を見よ。 ◎ This is observable using weak references. See tc39/proposal-weakrefs#31 for more detail.
それは、次の手続きを遂行する: ◎ It performs the following steps:
- %controller.`pullAlgorithm$rsdC ~SET `undefined^jv ◎ Set controller.[[pullAlgorithm]] to undefined.
- %controller.`cancelAlgorithm$rsdC ~SET `undefined^jv ◎ Set controller.[[cancelAlgorithm]] to undefined.
- %controller.`strategySizeAlgorithm$rsdC ~SET `undefined^jv ◎ Set controller.[[strategySizeAlgorithm]] to undefined.
`ReadableStreamDefaultControllerClose(controller)@A は、次の手続きを遂行する: ◎ ReadableStreamDefaultControllerClose(controller) performs the following steps:
- ~IF[ ~NOABRUPT `ReadableStreamDefaultControllerCanCloseOrEnqueue$A( %controller ) ~EQ ~F ] ⇒ ~RET ◎ If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) is false, return.
- %stream ~LET %controller.`stream$rsdC ◎ Let stream be controller.[[stream]].
- %controller.`closeRequested$rsdC ~SET ~T ◎ Set controller.[[closeRequested]] to true.
-
~IF[ %controller.`queue$rsdC は`空$である ]: ◎ If controller.[[queue]] is empty,
- ~NOABRUPT `ReadableStreamDefaultControllerClearAlgorithms$A( %controller ) ◎ Perform ! ReadableStreamDefaultControllerClearAlgorithms(controller).
- ~NOABRUPT `ReadableStreamClose$A( %stream ) ◎ Perform ! ReadableStreamClose(stream).
`ReadableStreamDefaultControllerEnqueue(controller, chunk)@A は、次の手続きを遂行する: ◎ ReadableStreamDefaultControllerEnqueue(controller, chunk) performs the following steps:
- ~IF[ ~NOABRUPT `ReadableStreamDefaultControllerCanCloseOrEnqueue$A( %controller ) ~EQ ~F ] ⇒ ~RET ◎ If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) is false, return.
- %stream ~LET %controller.`stream$rsdC ◎ Let stream be controller.[[stream]].
- ~IF[ ~NOABRUPT `IsReadableStreamLocked$A( %stream ) ~EQ ~T ]~AND[ ~NOABRUPT `ReadableStreamGetNumReadRequests$A( %stream ) ~GT 0 ] ⇒ ~NOABRUPT `ReadableStreamFulfillReadRequest$A( %stream, %chunk, ~F ) ◎ If ! IsReadableStreamLocked(stream) is true and ! ReadableStreamGetNumReadRequests(stream) > 0, perform ! ReadableStreamFulfillReadRequest(stream, chunk, false).
-
~ELSE: ◎ Otherwise,
- %result ~LET 次を遂行した結果を`完了~record$として解釈した結果 ⇒ %controller.`strategySizeAlgorithm$rsdC( %chunk ) ◎ Let result be the result of performing controller.[[strategySizeAlgorithm]], passing in chunk, and interpreting the result as a completion record.
-
~IF[ %result は`中途完了^である ]: ◎ If result is an abrupt completion,
- ~NOABRUPT `ReadableStreamDefaultControllerError$A( %controller, %result.`Value^sl ) ◎ Perform ! ReadableStreamDefaultControllerError(controller, result.[[Value]]).
- ~RET %result ◎ Return result.
- %chunkSize ~LET %result.`Value^sl ◎ 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,
- ~NOABRUPT `ReadableStreamDefaultControllerError$A( %controller, %enqueueResult.`Value^sl ) ◎ Perform ! ReadableStreamDefaultControllerError(controller, enqueueResult.[[Value]]).
- ~RET %enqueueResult ◎ Return enqueueResult.
- ~NOABRUPT `ReadableStreamDefaultControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(controller).
`ReadableStreamDefaultControllerError(controller, e)@A は、次の手続きを遂行する: ◎ ReadableStreamDefaultControllerError(controller, e) performs the following steps:
- %stream ~LET %controller.`stream$rsdC ◎ Let stream be controller.[[stream]].
- ~IF[ %stream.`state$rS ~NEQ `readable^l ] ⇒ ~RET ◎ If stream.[[state]] is not "readable", return.
- ~NOABRUPT `ResetQueue$A( %controller ) ◎ Perform ! ResetQueue(controller).
- ~NOABRUPT `ReadableStreamDefaultControllerClearAlgorithms$A( %controller ) ◎ Perform ! ReadableStreamDefaultControllerClearAlgorithms(controller).
- ~NOABRUPT `ReadableStreamError$A( %stream, %e ) ◎ Perform ! ReadableStreamError(stream, e).
`ReadableStreamDefaultControllerGetDesiredSize(controller)@A は、次の手続きを遂行する: ◎ ReadableStreamDefaultControllerGetDesiredSize(controller) performs the following steps:
- %state ~LET %controller.`stream$rsdC.`state$rS ◎ Let state be controller.[[stream]].[[state]].
- ~IF[ %state ~EQ `errored^l ] ⇒ ~RET ~NULL ◎ If state is "errored", return null.
- ~IF[ %state ~EQ `closed^l ] ⇒ ~RET 0 ◎ If state is "closed", return 0.
- ~RET %controller.`strategyHWM$rsdC ~MINUS %controller.`queueTotalSize$rsdC ◎ Return controller.[[strategyHWM]] − controller.[[queueTotalSize]].
`ReadableStreamDefaultControllerHasBackpressure(controller)@A は、 `TransformStream$I の実装に利用される。 それは、次の手続きを遂行する: ◎ ReadableStreamDefaultControllerHasBackpressure(controller) is used in the implementation of TransformStream. It performs the following steps:
- ~IF[ ~NOABRUPT `ReadableStreamDefaultControllerShouldCallPull$A( %controller ) ~EQ ~T ] ⇒ ~RET ~F ◎ If ! ReadableStreamDefaultControllerShouldCallPull(controller) is true, return false.
- ~RET ~T ◎ Otherwise, return true.
`ReadableStreamDefaultControllerCanCloseOrEnqueue(controller)@A は、次の手続きを遂行する: ◎ ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) performs the following steps:
- %state ~LET %controller.`stream$rsdC.`state$rS ◎ Let state be controller.[[stream]].[[state]].
- ~IF[ %controller.`closeRequested$rsdC ~EQ ~F ]~AND[ %state ~EQ `readable^l ] ⇒ ~RET ~T ◎ If controller.[[closeRequested]] is false and state is "readable", return true.
- ~RET ~F ◎ Otherwise, return false.
注記: [ %controller.`closeRequested$rsdC ~EQ ~F ]でありつつ[ %state ~NEQ `readable^l ]になる事例は、 次のときに起こる: ◎ The case where controller.[[closeRequested]] is false, but state is not "readable", happens when\
-
%controller.`error(e)$rsdc
を介して,~streamが~errorにされたとき ◎ the stream is errored via controller.error(), or\ -
%controller.`close()$rsdc
が一度も~callされずに,~streamが — 例:%stream.`cancel(reason)$rs
の~callにより — ~closeされたとき ◎ when it is closed without its controller’s controller.close() method ever being called: e.g., if the stream was closed by a call to stream.cancel().
`SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm)@A は、次の手続きを遂行する: ◎ SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm) performs the following steps:
- ~Assert: %stream.`controller$rS ~EQ `undefined^jv ◎ Assert: stream.[[controller]] is undefined.
- %controller.`stream$rsdC ~SET %stream ◎ Set controller.[[stream]] to stream.
- ~NOABRUPT `ResetQueue$A( %controller ) ◎ Perform ! ResetQueue(controller).
- %controller の ⇒# .`started$rsdC ~SET ~F, .`closeRequested$rsdC ~SET ~F, .`pullAgain$rsdC ~SET ~F, .`pulling$rsdC ~SET ~F, .`strategySizeAlgorithm$rsdC ~SET %sizeAlgorithm, .`strategyHWM$rsdC ~SET %highWaterMark, .`pullAlgorithm$rsdC ~SET %pullAlgorithm, .`cancelAlgorithm$rsdC ~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.`controller$rS ~SET %controller ◎ Set stream.[[controller]] to controller.
- %startResult ~LET %startAlgorithm() (これは、例外を投出するかもしれない) ◎ Let startResult be the result of performing startAlgorithm. (This might throw an exception.)
-
%startPromise ~LET `解決される~promise$( %startResult ) ◎ Let startPromise be a promise resolved with startResult.
-
%startPromise の`充足-時$には: ◎ Upon fulfillment of startPromise,
- %controller.`started$rsdC ~SET ~T ◎ Set controller.[[started]] to true.
- ~Assert: %controller.`pulling$rsdC ~EQ ~F ◎ Assert: controller.[[pulling]] is false.
- ~Assert: %controller.`pullAgain$rsdC ~EQ ~F ◎ Assert: controller.[[pullAgain]] is false.
- ~NOABRUPT `ReadableStreamDefaultControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(controller).
-
事由 %r による %startPromise の`却下-時$には: ◎ Upon rejection of startPromise with reason r,
- ~NOABRUPT `ReadableStreamDefaultControllerError$A( %controller, %r ) ◎ Perform ! ReadableStreamDefaultControllerError(controller, r).
-
`SetUpReadableStreamDefaultControllerFromUnderlyingSource(stream, underlyingSource, underlyingSourceDict, highWaterMark, sizeAlgorithm)@A は、次の手続きを遂行する: ◎ SetUpReadableStreamDefaultControllerFromUnderlyingSource(stream, underlyingSource, underlyingSourceDict, highWaterMark, sizeAlgorithm) performs the following steps:
- %controller ~LET `新たな$ `ReadableStreamDefaultController$I ◎ Let controller be a new ReadableStreamDefaultController.
- %startAlgorithm ~LET 次を走らす~algo ⇒ ~RET `undefined^jv ◎ Let startAlgorithm be an algorithm that returns undefined.
- %pullAlgorithm ~LET 次を走らす~algo ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ Let pullAlgorithm be an algorithm that returns a promise resolved with undefined.
- %cancelAlgorithm ~LET 次を走らす~algo ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ Let cancelAlgorithm be an algorithm that returns a promise resolved with undefined.
- ~IF[ %underlyingSourceDict[ "`start$usc" ] ~NEQ ε ] ⇒ %startAlgorithm ~SET 次を走らす~algo ⇒ ~RET `~callback関数を呼出す$( %underlyingSourceDict[ "`start$usc" ], « %controller »【, `投出し直す^i ?】, %underlyingSource ) ◎ If underlyingSourceDict["start"] exists, then set startAlgorithm to an algorithm which returns the result of invoking underlyingSourceDict["start"] with argument list « controller » and callback this value underlyingSource.
- ~IF[ %underlyingSourceDict[ "`pull$usc" ] ~NEQ ε ] ⇒ %pullAlgorithm ~SET 次を走らす~algo ⇒ ~RET `~callback関数を呼出す$( %underlyingSourceDict[ "`pull$usc" ], « %controller », ε, %underlyingSource ) ◎ If underlyingSourceDict["pull"] exists, then set pullAlgorithm to an algorithm which returns the result of invoking underlyingSourceDict["pull"] with argument list « controller » and callback this value underlyingSource.
- ~IF[ %underlyingSourceDict[ "`cancel$usc" ] ~NEQ ε ] ⇒ %cancelAlgorithm ~SET 所与の ( %reason ) に対し,次を走らす~algo ⇒ ~RET `~callback関数を呼出す$( %underlyingSourceDict[ "`cancel$usc" ], « %reason », ε, %underlyingSource ) ◎ If underlyingSourceDict["cancel"] exists, then set cancelAlgorithm to an algorithm which takes an argument reason and returns the result of invoking underlyingSourceDict["cancel"] with argument list « reason » and callback this value underlyingSource.
- ~ABRUPT `SetUpReadableStreamDefaultController$A( ↓ ) ⇒# %stream, %controller, %startAlgorithm, %pullAlgorithm, %cancelAlgorithm, %highWaterMark, %sizeAlgorithm ◎ Perform ? SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm).
4.9.5. ~byte~stream制御器
`ReadableByteStreamControllerCallPullIfNeeded(controller)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerCallPullIfNeeded(controller) performs the following steps:
- %shouldPull ~LET ~NOABRUPT `ReadableByteStreamControllerShouldCallPull$A( %controller ) ◎ Let shouldPull be ! ReadableByteStreamControllerShouldCallPull(controller).
- ~IF[ %shouldPull ~EQ ~F ] ⇒ ~RET ◎ If shouldPull is false, return.
-
~IF[ %controller.`pulling$rbsC ~EQ ~T ]: ◎ If controller.[[pulling]] is true,
- %controller.`pullAgain$rbsC ~SET ~T ◎ Set controller.[[pullAgain]] to true.
- ~RET ◎ Return.
- ~Assert: %controller.`pullAgain$rbsC ~EQ ~F ◎ Assert: controller.[[pullAgain]] is false.
- %controller.`pulling$rbsC ~SET ~T ◎ Set controller.[[pulling]] to true.
-
%pullPromise ~LET %controller.`pullAlgorithm$rbsC() ◎ Let pullPromise be the result of performing controller.[[pullAlgorithm]].
-
%pullPromise の`充足-時$には: ◎ Upon fulfillment of pullPromise,
- %controller.`pulling$rbsC ~SET ~F ◎ Set controller.[[pulling]] to false.
-
~IF[ %controller.`pullAgain$rbsC ~EQ ~T ]: ◎ If controller.[[pullAgain]] is true,
- %controller.`pullAgain$rbsC ~SET ~F ◎ Set controller.[[pullAgain]] to false.
- ~NOABRUPT `ReadableByteStreamControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
-
事由 %e による %pullPromise の`却下-時$には: ◎ Upon rejection of pullPromise with reason e,
- ~NOABRUPT `ReadableByteStreamControllerError$A( %controller, %e ) ◎ Perform ! ReadableByteStreamControllerError(controller, e).
-
`ReadableByteStreamControllerClearAlgorithms(controller)@A は、[ ~streamが~closeされるか~errorして, 各種~algoが それ以上~実行されなくなったとき ]に~callされる。 これは、 各種~algoへの参照を除去して,[ `ReadableStream$I ~obj自体は まだ参照されていても, `下層~byte~source$は~garbage収集される ]ことを許可する。 ◎ ReadableByteStreamControllerClearAlgorithms(controller) 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 byte source object to be garbage collected even if the ReadableStream itself is still referenced.
注記: これは、 `弱い参照@https://github.com/tc39/proposal-weakrefs/$を利用すると観測-可能になる。 詳細は `tc39/proposal-weakrefs#31@https://github.com/tc39/proposal-weakrefs/issues/31$ を見よ。 ◎ This is observable using weak references. See tc39/proposal-weakrefs#31 for more detail.
それは、次の手続きを遂行する: ◎ It performs the following steps:
- %controller.`pullAlgorithm$rbsC ~SET `undefined^jv ◎ Set controller.[[pullAlgorithm]] to undefined.
- %controller.`cancelAlgorithm$rbsC ~SET `undefined^jv ◎ Set controller.[[cancelAlgorithm]] to undefined.
`ReadableByteStreamControllerClearPendingPullIntos(controller)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerClearPendingPullIntos(controller) performs the following steps:
- ~NOABRUPT `ReadableByteStreamControllerInvalidateBYOBRequest$A( %controller ) ◎ Perform ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).
- %controller.`pendingPullIntos$rbsC ~SET 新たな空`~list$ ◎ Set controller.[[pendingPullIntos]] to a new empty list.
`ReadableByteStreamControllerClose(controller)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerClose(controller) performs the following steps:
- %stream ~LET %controller.`stream$rbsC ◎ Let stream be controller.[[stream]].
- ~IF[ %controller.`closeRequested$rbsC ~EQ ~T ]~OR[ %stream.`state$rS ~NEQ `readable^l ] ⇒ ~RET ◎ If controller.[[closeRequested]] is true or stream.[[state]] is not "readable", return.
-
~IF[ %controller.`queueTotalSize$rbsC ~GT 0 ]: ◎ If controller.[[queueTotalSize]] > 0,
- %controller.`closeRequested$rbsC ~SET ~T ◎ Set controller.[[closeRequested]] to true.
- ~RET ◎ Return.
-
~IF[ %controller.`pendingPullIntos$rbsC は`空$でない ]: ◎ If controller.[[pendingPullIntos]] is not empty,
- %firstPendingPullInto ~LET %controller.`pendingPullIntos$rbsC[0] ◎ Let firstPendingPullInto be controller.[[pendingPullIntos]][0].
-
~IF[ `剰余$( %firstPendingPullInto の`埋まった~byte数$pD, %firstPendingPullInto の`要素~size$pD ) ~NEQ 0 ]: ◎ If the remainder after dividing firstPendingPullInto’s bytes filled by firstPendingPullInto’s element size is not 0,
- %e ~LET 新たな `TypeError$jE 例外 ◎ Let e be a new TypeError exception.
- ~NOABRUPT `ReadableByteStreamControllerError$A( %controller, %e ) ◎ Perform ! ReadableByteStreamControllerError(controller, e).
- ~THROW %e ◎ Throw e.
- ~NOABRUPT `ReadableByteStreamControllerClearAlgorithms$A( %controller ) ◎ Perform ! ReadableByteStreamControllerClearAlgorithms(controller).
- ~NOABRUPT `ReadableStreamClose$A( %stream ) ◎ Perform ! ReadableStreamClose(stream).
`ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor) performs the following steps:
- ~Assert: %stream.`state$rS ~NEQ `errored^l ◎ Assert: stream.[[state]] is not "errored".
- ~Assert: %pullIntoDescriptor の`読取器~型$pD ~NEQ `none^l ◎ Assert: pullIntoDescriptor.reader type is not "none".
- %done ~LET ~F ◎ Let done be false.
-
~IF[ %stream.`state$rS ~EQ `closed^l ]: ◎ If stream.[[state]] is "closed",
- ~Assert: `剰余$( %pullIntoDescriptor の`埋まった~byte数$pD, %pullIntoDescriptor の`要素~size$pD ) ~EQ 0 ◎ Assert: the remainder after dividing pullIntoDescriptor’s bytes filled by pullIntoDescriptor’s element size is 0.
- %done ~SET ~T ◎ Set done to true.
- %filledView ~LET ~NOABRUPT `ReadableByteStreamControllerConvertPullIntoDescriptor$A( %pullIntoDescriptor ) ◎ Let filledView be ! ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
-
~IF[ %pullIntoDescriptor の`読取器~型$pD ~EQ `default^l ]: ◎ If pullIntoDescriptor’s reader type is "default",
- ~NOABRUPT `ReadableStreamFulfillReadRequest$A( %stream, %filledView, %done ) ◎ Perform ! ReadableStreamFulfillReadRequest(stream, filledView, done).
-
~ELSE: ◎ Otherwise,
- ~Assert: %pullIntoDescriptor の`読取器~型$pD ~EQ `byob^l ◎ Assert: pullIntoDescriptor’s reader type is "byob".
- ~NOABRUPT `ReadableStreamFulfillReadIntoRequest$A( %stream, %filledView, %done ) ◎ Perform ! ReadableStreamFulfillReadIntoRequest(stream, filledView, done).
`ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor) performs the following steps:
- %bytesFilled ~LET %pullIntoDescriptor の`埋まった~byte数$pD ◎ Let bytesFilled be pullIntoDescriptor’s bytes filled.
- %elementSize ~LET %pullIntoDescriptor の`要素~size$pD ◎ Let elementSize be pullIntoDescriptor’s element size.
- ~Assert: %bytesFilled ~LTE %pullIntoDescriptor の`~byte長さ$pD ◎ Assert: bytesFilled ≤ pullIntoDescriptor’s byte length.
- ~Assert: `剰余$( %bytesFilled, %elementSize ) ~EQ 0 ◎ Assert: the remainder after dividing bytesFilled by elementSize is 0.
- %buffer ~LET ~NOABRUPT `TransferArrayBuffer$A( %pullIntoDescriptor の`~buffer$pD ) ◎ Let buffer be ! TransferArrayBuffer(pullIntoDescriptor’s buffer).
- ~RET ~NOABRUPT `Construct$Ax( %pullIntoDescriptor の`~view構築子$pD, « %buffer, %pullIntoDescriptor の`~byte~offset$pD, %bytesFilled ~DIV %elementSize » ) ◎ Return ! Construct(pullIntoDescriptor’s view constructor, « buffer, pullIntoDescriptor’s byte offset, bytesFilled ÷ elementSize »).
`ReadableByteStreamControllerEnqueue(controller, chunk)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerEnqueue(controller, chunk) performs the following steps:
- %stream ~LET %controller.`stream$rbsC ◎ Let stream be controller.[[stream]].
- ~IF[ %controller.`closeRequested$rbsC ~EQ ~T ]~OR[ %stream.`state$rS ~NEQ `readable^l ] ⇒ ~RET ◎ If controller.[[closeRequested]] is true or stream.[[state]] is not "readable", return.
- %buffer ~LET %chunk.`ViewedArrayBuffer^sl ◎ Let buffer be chunk.[[ViewedArrayBuffer]].
- %byteOffset ~LET %chunk.`ByteOffset^sl ◎ Let byteOffset be chunk.[[ByteOffset]].
- %byteLength ~LET %chunk.`ByteLength^sl ◎ Let byteLength be chunk.[[ByteLength]].
- ~IF[ ~NOABRUPT `IsDetachedBuffer$Ax( %buffer ) ~EQ ~T ] ⇒ ~THROW `TypeError$jE ◎ If ! IsDetachedBuffer(buffer) is true, throw a TypeError exception.
- %transferredBuffer ~LET ~ABRUPT `TransferArrayBuffer$A( %buffer ) ◎ Let transferredBuffer be ? TransferArrayBuffer(buffer).
-
~IF[ %controller.`pendingPullIntos$rbsC は`空$でない ]: ◎ If controller.[[pendingPullIntos]] is not empty,
- %firstPendingPullInto ~LET %controller.`pendingPullIntos$rbsC[0] ◎ Let firstPendingPullInto be controller.[[pendingPullIntos]][0].
- ~IF[ ~NOABRUPT `IsDetachedBuffer$Ax( %firstPendingPullInto の`~buffer$pD ) ~EQ ~T ] ⇒ ~THROW `TypeError$jE ◎ If ! IsDetachedBuffer(firstPendingPullInto’s buffer) is true, throw a TypeError exception.
- ~NOABRUPT `ReadableByteStreamControllerInvalidateBYOBRequest$A( %controller ) ◎ Perform ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).
- %firstPendingPullInto の`~buffer$pD ~SET ~NOABRUPT `TransferArrayBuffer$A( %firstPendingPullInto の`~buffer$pD ) ◎ Set firstPendingPullInto’s buffer to ! TransferArrayBuffer(firstPendingPullInto’s buffer).
- ~IF[ %firstPendingPullInto の`読取器~型$pD ~EQ `none^l ] ⇒ ~ABRUPT `ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue$A( %controller, %firstPendingPullInto ) ◎ If firstPendingPullInto’s reader type is "none", perform ? ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(controller, firstPendingPullInto).
-
~IF[ ~NOABRUPT `ReadableStreamHasDefaultReader$A( %stream ) ~EQ ~T ]: ◎ If ! ReadableStreamHasDefaultReader(stream) is true,
- ~NOABRUPT `ReadableByteStreamControllerProcessReadRequestsUsingQueue$A( %controller ) ◎ Perform ! ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller).
-
~IF[ ~NOABRUPT `ReadableStreamGetNumReadRequests$A( %stream ) ~EQ 0 ]: ◎ If ! ReadableStreamGetNumReadRequests(stream) is 0,
- ~Assert: %controller.`pendingPullIntos$rbsC は`空$である ◎ Assert: controller.[[pendingPullIntos]] is empty.
- ~NOABRUPT `ReadableByteStreamControllerEnqueueChunkToQueue$A( %controller, %transferredBuffer, %byteOffset, %byteLength ) ◎ Perform ! ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength).
-
~ELSE: ◎ Otherwise,
- ~Assert: %controller.`queue$rbsC は`空$である ◎ Assert: controller.[[queue]] is empty.
-
~IF[ %controller.`pendingPullIntos$rbsC は`空$でない ]: ◎ If controller.[[pendingPullIntos]] is not empty,
- ~Assert: %controller.`pendingPullIntos$rbsC[0] の`読取器~型$pD ~EQ `default^l ◎ Assert: controller.[[pendingPullIntos]][0]'s reader type is "default".
- ~NOABRUPT `ReadableByteStreamControllerShiftPendingPullInto$A( %controller ) ◎ Perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).
- %transferredView ~LET ~NOABRUPT `Construct$Ax( `Uint8Array$jI, « %transferredBuffer, %byteOffset, %byteLength » ) ◎ Let transferredView be ! Construct(%Uint8Array%, « transferredBuffer, byteOffset, byteLength »).
- ~NOABRUPT `ReadableStreamFulfillReadRequest$A( %stream, %transferredView, ~F ) ◎ Perform ! ReadableStreamFulfillReadRequest(stream, transferredView, false).
-
~ELIF[ ~NOABRUPT `ReadableStreamHasBYOBReader$A( %stream ) ~EQ ~T ]: ◎ Otherwise, if ! ReadableStreamHasBYOBReader(stream) is true,
- ~NOABRUPT `ReadableByteStreamControllerEnqueueChunkToQueue$A( %controller, %transferredBuffer, %byteOffset, %byteLength ) ◎ Perform ! ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength).
- ~NOABRUPT `ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue$A( %controller ) ◎ Perform ! ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
-
~ELSE: ◎ Otherwise,
- ~Assert: ~NOABRUPT `IsReadableStreamLocked$A( %stream ) ~EQ ~F ◎ Assert: ! IsReadableStreamLocked(stream) is false.
- ~NOABRUPT `ReadableByteStreamControllerEnqueueChunkToQueue$A( %controller, %transferredBuffer, %byteOffset, %byteLength ) ◎ Perform ! ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength).
- ~NOABRUPT `ReadableByteStreamControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
`ReadableByteStreamControllerEnqueueChunkToQueue(controller, buffer, byteOffset, byteLength)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerEnqueueChunkToQueue(controller, buffer, byteOffset, byteLength) performs the following steps:
- %controller.`queue$rbsC に[ 次を伴う,新たな`可読~byte~stream用の~queue~entry$ ]を`付加する$ ⇒# `~buffer$qE ~SET %buffer, `~byte~offset$qE ~SET %byteOffset, `~byte長さ$qE ~SET %byteLength ◎ Append a new readable byte stream queue entry with buffer buffer, byte offset byteOffset, and byte length byteLength to controller.[[queue]].
- %controller.`queueTotalSize$rbsC ~INCBY %byteLength ◎ Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]] + byteLength.
`ReadableByteStreamControllerEnqueueClonedChunkToQueue(controller, buffer, byteOffset, byteLength)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerEnqueueClonedChunkToQueue(controller, buffer, byteOffset, byteLength) performs the following steps:
- %cloneResult ~LET `CloneArrayBuffer$Ax( %buffer, %byteOffset, %byteLength, `ArrayBuffer$jI ) ◎ Let cloneResult be CloneArrayBuffer(buffer, byteOffset, byteLength, %ArrayBuffer%).
-
~IF[ %cloneResult は`中途完了^である ]: ◎ If cloneResult is an abrupt completion,
- ~NOABRUPT `ReadableByteStreamControllerError$A( %controller, %cloneResult.`Value^sl ) ◎ Perform ! ReadableByteStreamControllerError(controller, cloneResult.[[Value]]).
- ~RET %cloneResult ◎ Return cloneResult.
- ~NOABRUPT `ReadableByteStreamControllerEnqueueChunkToQueue$A( %controller, %cloneResult.`Value^sl, 0, %byteLength ) ◎ Perform ! ReadableByteStreamControllerEnqueueChunkToQueue(controller, cloneResult.[[Value]], 0, byteLength).
`ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(controller, pullIntoDescriptor)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(controller, pullIntoDescriptor) performs the following steps:
- ~Assert: %pullIntoDescriptor の`読取器~型$pD ~EQ `none^l ◎ Assert: pullIntoDescriptor’s reader type is "none".
- ~IF[ %pullIntoDescriptor の`埋まった~byte数$pD ~GT 0 ] ⇒ ~ABRUPT `ReadableByteStreamControllerEnqueueClonedChunkToQueue$A( %controller, %pullIntoDescriptor の`~buffer$pD, %pullIntoDescriptor の`~byte~offset$pD, %pullIntoDescriptor の`埋まった~byte数$pD ) ◎ If pullIntoDescriptor’s bytes filled > 0, perform ? ReadableByteStreamControllerEnqueueClonedChunkToQueue(controller, pullIntoDescriptor’s buffer, pullIntoDescriptor’s byte offset, pullIntoDescriptor’s bytes filled).
- ~NOABRUPT `ReadableByteStreamControllerShiftPendingPullInto$A( %controller ) ◎ Perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).
`ReadableByteStreamControllerError(controller, e)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerError(controller, e) performs the following steps:
- %stream ~LET %controller.`stream$rbsC ◎ Let stream be controller.[[stream]].
- ~IF[ %stream.`state$rS ~NEQ `readable^l ] ⇒ ~RET ◎ If stream.[[state]] is not "readable", return.
- ~NOABRUPT `ReadableByteStreamControllerClearPendingPullIntos$A( %controller ) ◎ Perform ! ReadableByteStreamControllerClearPendingPullIntos(controller).
- ~NOABRUPT `ResetQueue$A( %controller ) ◎ Perform ! ResetQueue(controller).
- ~NOABRUPT `ReadableByteStreamControllerClearAlgorithms$A( %controller ) ◎ Perform ! ReadableByteStreamControllerClearAlgorithms(controller).
- ~NOABRUPT `ReadableStreamError$A( %stream, %e ) ◎ Perform ! ReadableStreamError(stream, e).
`ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, size, pullIntoDescriptor)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, size, pullIntoDescriptor) performs the following steps:
- ~Assert:[ %controller.`pendingPullIntos$rbsC は`空$である ]~OR[ %controller.`pendingPullIntos$rbsC[0] ~EQ %pullIntoDescriptor ] ◎ Assert: either controller.[[pendingPullIntos]] is empty, or controller.[[pendingPullIntos]][0] is pullIntoDescriptor.
- ~Assert: %controller.`byobRequest$rbsC ~EQ ~NULL ◎ Assert: controller.[[byobRequest]] is null.
- %pullIntoDescriptor の`埋まった~byte数$pD ~INCBY %size ◎ Set pullIntoDescriptor’s bytes filled to bytes filled + size.
`ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) performs the following steps:
- %maxBytesToCopy ~LET `min^op( %controller.`queueTotalSize$rbsC, ( %pullIntoDescriptor の`~byte長さ$pD ~MINUS %pullIntoDescriptor の`埋まった~byte数$pD ) ) ◎ Let maxBytesToCopy be min(controller.[[queueTotalSize]], pullIntoDescriptor’s byte length − pullIntoDescriptor’s bytes filled).
- %maxBytesFilled ~LET ( %pullIntoDescriptor の`埋まった~byte数$pD ~PLUS %maxBytesToCopy ) ◎ Let maxBytesFilled be pullIntoDescriptor’s bytes filled + maxBytesToCopy.
- %totalBytesToCopyRemaining ~LET %maxBytesToCopy ◎ Let totalBytesToCopyRemaining be maxBytesToCopy.
- %ready ~LET ~F ◎ Let ready be false.
- ~Assert: %pullIntoDescriptor の`埋まった~byte数$pD ~LT %pullIntoDescriptor の`最小な埋n$pD ◎ Assert: pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s minimum fill.
- %remainderBytes ~LET `剰余$( %maxBytesFilled, %pullIntoDescriptor の`要素~size$pD ) ◎ Let remainderBytes be the remainder after dividing maxBytesFilled by pullIntoDescriptor’s element size.
- %maxAlignedBytes ~LET %maxBytesFilled ~MINUS %remainderBytes ◎ Let maxAlignedBytes be maxBytesFilled − remainderBytes.
-
~IF[ %maxAlignedBytes ~GTE %pullIntoDescriptor の`最小な埋n$pD ]: ◎ If maxAlignedBytes ≥ pullIntoDescriptor’s minimum fill,
- %totalBytesToCopyRemaining ~SET %maxAlignedBytes ~MINUS %pullIntoDescriptor の`埋まった~byte数$pD ◎ Set totalBytesToCopyRemaining to maxAlignedBytes − pullIntoDescriptor’s bytes filled.
-
%ready ~SET ~T ◎ Set ready to true.
注記: `read()$byob 要請~用の記述子【 %pullIntoDescriptor 】は、 まだ その最小~長さまで埋まってない間は,当の~queueを成す頭部に居続けることになる — なので、 `下層~source$は,それを埋め続けれる。 ◎ A descriptor for a read() request that is not yet filled up to its minimum length will stay at the head of the queue, so the underlying source can keep filling it.
- %queue ~LET %controller.`queue$rbsC ◎ Let queue be controller.[[queue]].
-
~WHILE[ %totalBytesToCopyRemaining ~GT 0 ]: ◎ While totalBytesToCopyRemaining > 0,
- %headOfQueue ~LET %queue[0] ◎ Let headOfQueue be queue[0].
- %bytesToCopy ~LET `min^op( %totalBytesToCopyRemaining, %headOfQueue の`~byte長さ$qE ) ◎ Let bytesToCopy be min(totalBytesToCopyRemaining, headOfQueue’s byte length).
- %destStart ~LET ( %pullIntoDescriptor の`~byte~offset$pD ~PLUS %pullIntoDescriptor の`埋まった~byte数$pD ) ◎ Let destStart be pullIntoDescriptor’s byte offset + pullIntoDescriptor’s bytes filled.
- ~NOABRUPT `CopyDataBlockBytes$Ax( %pullIntoDescriptor の`~buffer$pD.`ArrayBufferData^sl, %destStart, %headOfQueue の`~buffer$qE.`ArrayBufferData^sl, %headOfQueue の`~byte~offset$qE, %bytesToCopy ) ◎ Perform ! CopyDataBlockBytes(pullIntoDescriptor’s buffer.[[ArrayBufferData]], destStart, headOfQueue’s buffer.[[ArrayBufferData]], headOfQueue’s byte offset, bytesToCopy).
-
~IF[ %headOfQueue の`~byte長さ$qE ~EQ %bytesToCopy ]: ◎ If headOfQueue’s byte length is bytesToCopy,
- %queue[0] を`除去する$ ◎ Remove queue[0].
-
~ELSE: ◎ Otherwise,
- %headOfQueue の`~byte~offset$qE ~INCBY %bytesToCopy ◎ Set headOfQueue’s byte offset to headOfQueue’s byte offset + bytesToCopy.
- %headOfQueue の`~byte長さ$qE ~DECBY %bytesToCopy ◎ Set headOfQueue’s byte length to headOfQueue’s byte length − bytesToCopy.
- %controller.`queueTotalSize$rbsC ~DECBY %bytesToCopy ◎ Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]] − bytesToCopy.
- ~NOABRUPT `ReadableByteStreamControllerFillHeadPullIntoDescriptor$A( %controller, %bytesToCopy, %pullIntoDescriptor ) ◎ Perform ! ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesToCopy, pullIntoDescriptor).
- %totalBytesToCopyRemaining ~DECBY %bytesToCopy ◎ Set totalBytesToCopyRemaining to totalBytesToCopyRemaining − bytesToCopy.
-
~IF[ %ready ~EQ ~F ]: ◎ If ready is false,
- ~Assert: %controller.`queueTotalSize$rbsC ~EQ 0 ◎ Assert: controller.[[queueTotalSize]] is 0.
- ~Assert: %pullIntoDescriptor の`埋まった~byte数$pD ~GT 0 ◎ Assert: pullIntoDescriptor’s bytes filled > 0.
- ~Assert: %pullIntoDescriptor の`埋まった~byte数$pD ~LT %pullIntoDescriptor の`最小な埋n$pD ◎ Assert: pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s minimum fill.
- ~RET %ready ◎ Return ready.
`ReadableByteStreamControllerFillReadRequestFromQueue(controller, readRequest)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerFillReadRequestFromQueue(controller, readRequest) performs the following steps:
- ~Assert: %controller.`queueTotalSize$rbsC ~GT 0 ◎ Assert: controller.[[queueTotalSize]] > 0.
- %entry ~LET %controller.`queue$rbsC[ 0 ] ◎ Let entry be controller.[[queue]][0].
- %controller.`queue$rbsC から %entry を`除去する$ ◎ Remove entry from controller.[[queue]].
- %controller.`queueTotalSize$rbsC ~SET %controller.`queueTotalSize$rbsC ~MINUS %entry の`~byte長さ$qE ◎ Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]] − entry’s byte length.
- ~NOABRUPT `ReadableByteStreamControllerHandleQueueDrain$A( %controller ) ◎ Perform ! ReadableByteStreamControllerHandleQueueDrain(controller).
- %view ~LET ~NOABRUPT `Construct$Ax( `Uint8Array$jI, « %entry の`~buffer$qE, %entry の`~byte~offset$qE, %entry の`~byte長さ$qE » ) ◎ Let view be ! Construct(%Uint8Array%, « entry’s buffer, entry’s byte offset, entry’s byte length »).
- %readRequest の`~chunk手続き$rR( %view ) ◎ Perform readRequest’s chunk steps, given view.
`ReadableByteStreamControllerGetBYOBRequest(controller)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerGetBYOBRequest(controller) performs the following steps:
-
~IF[ %controller.`byobRequest$rbsC ~EQ ~NULL ]~AND[ %controller.`pendingPullIntos$rbsC は`空$でない ]: ◎ If controller.[[byobRequest]] is null and controller.[[pendingPullIntos]] is not empty,
- %firstDescriptor ~LET %controller.`pendingPullIntos$rbsC[ 0 ] ◎ Let firstDescriptor be controller.[[pendingPullIntos]][0].
- %view ~LET ~NOABRUPT `Construct$Ax( `有型~配列$, « 次に挙げる~item » ) ⇒# %firstDescriptor の`~buffer$pD, %firstDescriptor の`~byte~offset$pD ~PLUS %firstDescriptor の`埋まった~byte数$pD, %firstDescriptor の`~byte長さ$pD ~MINUS %firstDescriptor の`埋まった~byte数$pD ◎ Let view be ! Construct(%Uint8Array%, « firstDescriptor’s buffer, firstDescriptor’s byte offset + firstDescriptor’s bytes filled, firstDescriptor’s byte length − firstDescriptor’s bytes filled »).
- %byobRequest ~LET `新たな$ `ReadableStreamBYOBRequest$I ◎ Let byobRequest be a new ReadableStreamBYOBRequest.
- %byobRequest.`controller$bbrQ ~SET %controller ◎ Set byobRequest.[[controller]] to controller.
- %byobRequest.`view$bbrQ ~SET %view ◎ Set byobRequest.[[view]] to view.
- %controller.`byobRequest$rbsC ~SET %byobRequest ◎ Set controller.[[byobRequest]] to byobRequest.
- ~RET %controller.`byobRequest$rbsC ◎ Return controller.[[byobRequest]].
`ReadableByteStreamControllerGetDesiredSize(controller)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerGetDesiredSize(controller) performs the following steps:
- %state ~LET %controller.`stream$rbsC.`state$rS ◎ Let state be controller.[[stream]].[[state]].
- ~IF[ %state ~EQ `errored^l ] ⇒ ~RET ~NULL ◎ If state is "errored", return null.
- ~IF[ %state ~EQ `closed^l ] ⇒ ~RET 0 ◎ If state is "closed", return 0.
- ~RET %controller.`strategyHWM$rbsC ~MINUS %controller.`queueTotalSize$rbsC ◎ Return controller.[[strategyHWM]] − controller.[[queueTotalSize]].
`ReadableByteStreamControllerHandleQueueDrain(controller)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerHandleQueueDrain(controller) performs the following steps:
- ~Assert: %controller.`stream$rbsC.`state$rS ~EQ `readable^l ◎ Assert: controller.[[stream]].[[state]] is "readable".
-
~IF[ %controller.`queueTotalSize$rbsC ~EQ 0 ]~AND[ %controller.`closeRequested$rbsC ~EQ ~T ]: ◎ If controller.[[queueTotalSize]] is 0 and controller.[[closeRequested]] is true,
- ~NOABRUPT `ReadableByteStreamControllerClearAlgorithms$A( %controller ) ◎ Perform ! ReadableByteStreamControllerClearAlgorithms(controller).
- ~NOABRUPT `ReadableStreamClose$A( %controller.`stream$rbsC ) ◎ Perform ! ReadableStreamClose(controller.[[stream]]).
-
~ELSE: ◎ Otherwise,
- ~NOABRUPT `ReadableByteStreamControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
`ReadableByteStreamControllerInvalidateBYOBRequest(controller)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerInvalidateBYOBRequest(controller) performs the following steps:
- ~IF[ %controller.`byobRequest$rbsC ~EQ ~NULL ] ⇒ ~RET ◎ If controller.[[byobRequest]] is null, return.
- %controller.`byobRequest$rbsC.`controller$bbrQ ~SET `undefined^jv ◎ Set controller.[[byobRequest]].[[controller]] to undefined.
- %controller.`byobRequest$rbsC.`view$bbrQ ~SET ~NULL ◎ Set controller.[[byobRequest]].[[view]] to null.
- %controller.`byobRequest$rbsC ~SET ~NULL ◎ Set controller.[[byobRequest]] to null.
`ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller) performs the following steps:
- ~Assert: %controller.`closeRequested$rbsC ~EQ ~F ◎ Assert: controller.[[closeRequested]] is false.
-
~WHILE[ %controller.`pendingPullIntos$rbsC は`空$でない ]: ◎ While controller.[[pendingPullIntos]] is not empty,
- ~IF[ %controller.`queueTotalSize$rbsC ~EQ 0 ] ⇒ ~RET ◎ If controller.[[queueTotalSize]] is 0, return.
- %pullIntoDescriptor ~LET %controller.`pendingPullIntos$rbsC[0] ◎ Let pullIntoDescriptor be controller.[[pendingPullIntos]][0].
-
~IF[ ~NOABRUPT `ReadableByteStreamControllerFillPullIntoDescriptorFromQueue$A( %controller, %pullIntoDescriptor ) ~EQ ~T ]: ◎ If ! ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) is true,
- ~NOABRUPT `ReadableByteStreamControllerShiftPendingPullInto$A( %controller ) ◎ Perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).
- ~NOABRUPT `ReadableByteStreamControllerCommitPullIntoDescriptor$A( %controller.`stream$rbsC, %pullIntoDescriptor) ◎ Perform ! ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]], pullIntoDescriptor).
`ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller) performs the following steps:
- %reader ~LET %controller.`stream$rbsC.`reader$rS ◎ Let reader be controller.[[stream]].[[reader]].
- ~Assert: %reader は `ReadableStreamDefaultReader$I を`実装する$ ◎ Assert: reader implements ReadableStreamDefaultReader.
-
~WHILE[ %reader.`readRequests$rsR は`空$でない ]: ◎ While reader.[[readRequests]] is not empty,
- ~IF[ %controller.`queueTotalSize$rbsC ~EQ 0 ] ⇒ ~RET ◎ If controller.[[queueTotalSize]] is 0, return.
- %readRequest ~LET %reader.`readRequests$rsR[ 0 ] ◎ Let readRequest be reader.[[readRequests]][0].
- %reader.`readRequests$rsR から %readRequest を`除去する$ ◎ Remove readRequest from reader.[[readRequests]].
- ~NOABRUPT `ReadableByteStreamControllerFillReadRequestFromQueue$A( %controller, %readRequest ) ◎ Perform ! ReadableByteStreamControllerFillReadRequestFromQueue(controller, readRequest).
`ReadableByteStreamControllerPullInto(controller, view, min, readIntoRequest)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerPullInto(controller, view, min, readIntoRequest) performs the following steps:
- %stream ~LET %controller.`stream$rbsC ◎ Let stream be controller.[[stream]].
- %elementSizem ~LET 1 ◎ Let elementSize be 1.
- %ctor ~LET `DataView$jI ◎ Let ctor be %DataView%.
- ~IF[ %view は `TypedArrayName^sl 内部~slotを有する(すなわち, `DataView$I ではない) ] ⇒ ( %elementSizem, %ctor ) ~SET `有型~配列 構築子 表t@~TC39#sec-dataview-objects$ に指定される, %view.`TypedArrayName^sl 用の ( 要素~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]].
- %minimumFill ~LET %min ~MUL %elementSize ◎ Let minimumFill be min × elementSize.
- ~Assert: %minimumFill ~GTE 0 ]~AND[ %minimumFill ~LTE %view.`ByteLength^sl ] ◎ Assert: minimumFill ≥ 0 and minimumFill ≤ view.[[ByteLength]].
- ~Assert: `剰余$( %minimumFill, %elementSize ) ~EQ 0 ◎ Assert: the remainder after dividing minimumFill by elementSize is 0.
- %byteOffset ~LET %view.`ByteOffset^sl ◎ Let byteOffset be view.[[ByteOffset]].
- %byteLength ~LET %view.`ByteLength^sl ◎ Let byteLength be view.[[ByteLength]].
- %bufferResult ~LET `TransferArrayBuffer$A( %view.`ViewedArrayBuffer^sl ) ◎ Let bufferResult be TransferArrayBuffer(view.[[ViewedArrayBuffer]]).
-
~IF[ %bufferResult は`中途完了^である ]: ◎ If bufferResult is an abrupt completion,
- %readIntoRequest の`~error手続き$riR( %bufferResult.`Value^sl ) ◎ Perform readIntoRequest’s error steps, given bufferResult.[[Value]].
- ~RET ◎ Return.
- %buffer ~LET %bufferResult.`Value^sl ◎ Let buffer be bufferResult.[[Value]].
- %pullIntoDescriptor ~LET 次を伴う,新たな`~pull~into記述子$ ⇒# `~buffer$pD ~SET %buffer, `~buffer~byte長さ$pD ~SET %buffer.`ArrayBufferByteLength^sl, `~byte~offset$pD ~SET %byteOffset, `~byte長さ$pD ~SET %byteLength, `埋まった~byte数$pD ~SET 0, `最小な埋n$pD ~SET %minimumFill, `要素~size$pD ~SET %elementSize, `~view構築子$pD ~SET %ctor, `読取器~型$pD ~SET `byob^l ◎ Let pullIntoDescriptor be a new pull-into descriptor with ◎ buffer • buffer buffer byte length • buffer.[[ArrayBufferByteLength]] byte offset • byteOffset byte length • byteLength bytes filled • 0 minimum fill • minimumFill element size • elementSize view constructor • ctor reader type • "byob"
-
~IF[ %controller.`pendingPullIntos$rbsC は空でない ]: ◎ If controller.[[pendingPullIntos]] is not empty,
- %controller.`pendingPullIntos$rbsC に %pullIntoDescriptor を`付加する$ ◎ Append pullIntoDescriptor to controller.[[pendingPullIntos]].
- ~NOABRUPT `ReadableStreamAddReadIntoRequest$A( %stream, %readIntoRequest ) ◎ Perform ! ReadableStreamAddReadIntoRequest(stream, readIntoRequest).
- ~RET ◎ Return.
-
~IF[ %stream.`state$rS ~EQ `closed^l ]: ◎ If stream.[[state]] is "closed",
- %emptyView ~LET ~NOABRUPT `Construct$Ax( %ctor, « %pullIntoDescriptor の`~buffer$pD, %pullIntoDescriptor の`~byte~offset$pD, 0 » ) ◎ Let emptyView be ! Construct(ctor, « pullIntoDescriptor’s buffer, pullIntoDescriptor’s byte offset, 0 »).
- %readIntoRequest の`~close手続き$riR( %emptyView ) ◎ Perform readIntoRequest’s close steps, given emptyView.
- ~RET ◎ Return.
-
~IF[ %controller.`queueTotalSize$rbsC ~GT 0 ]: ◎ If controller.[[queueTotalSize]] > 0,
-
~IF[ ~NOABRUPT `ReadableByteStreamControllerFillPullIntoDescriptorFromQueue$A( %controller, %pullIntoDescriptor ) ~EQ ~T ]: ◎ If ! ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) is true,
- %filledView ~LET ~NOABRUPT `ReadableByteStreamControllerConvertPullIntoDescriptor$A( %pullIntoDescriptor ) ◎ Let filledView be ! ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
- ~NOABRUPT `ReadableByteStreamControllerHandleQueueDrain$A( %controller ) ◎ Perform ! ReadableByteStreamControllerHandleQueueDrain(controller).
- %readIntoRequest の`~chunk手続き$riR( %filledView ) ◎ Perform readIntoRequest’s chunk steps, given filledView.
- ~RET ◎ Return.
-
~IF[ %controller.`closeRequested$rbsC ~EQ ~T ]: ◎ If controller.[[closeRequested]] is true,
- %e ~LET `TypeError$jE 例外 ◎ Let e be a TypeError exception.
- ~NOABRUPT `ReadableByteStreamControllerError$A( %controller, %e ) ◎ Perform ! ReadableByteStreamControllerError(controller, e).
- %readIntoRequest の`~error手続き$riR( %e ) ◎ Perform readIntoRequest’s error steps, given e.
- ~RET ◎ Return.
-
- %controller.`pendingPullIntos$rbsC に %pullIntoDescriptor を`付加する$ ◎ Append pullIntoDescriptor to controller.[[pendingPullIntos]].
- ~NOABRUPT `ReadableStreamAddReadIntoRequest$A( %stream, %readIntoRequest ) ◎ Perform ! ReadableStreamAddReadIntoRequest(stream, readIntoRequest).
- ~NOABRUPT `ReadableByteStreamControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
`ReadableByteStreamControllerRespond(controller, bytesWritten)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerRespond(controller, bytesWritten) performs the following steps:
- ~Assert: %controller.`pendingPullIntos$rbsC は`空$でない ◎ Assert: controller.[[pendingPullIntos]] is not empty.
- %firstDescriptor ~LET %controller.`pendingPullIntos$rbsC[0] ◎ Let firstDescriptor be controller.[[pendingPullIntos]][0].
- %state ~LET %controller.`stream$rbsC.`state$rS ◎ Let state be controller.[[stream]].[[state]].
-
~IF[ %state ~EQ `closed^l ]: ◎ If state is "closed",
- ~IF[ %bytesWritten ~NEQ 0 ] ⇒ ~THROW `TypeError$jE ◎ If bytesWritten is not 0, throw a TypeError exception.
-
~ELSE: ◎ Otherwise,
- ~Assert: %state ~EQ `readable^l ◎ Assert: state is "readable".
- ~IF[ %bytesWritten ~EQ 0 ] ⇒ ~THROW `TypeError$jE ◎ If bytesWritten is 0, throw a TypeError exception.
- ~IF[ %firstDescriptor の`埋まった~byte数$pD ~PLUS %bytesWritten ~GT %firstDescriptor の`~byte長さ$pD ] ⇒ ~THROW `RangeError$E ◎ If firstDescriptor’s bytes filled + bytesWritten > firstDescriptor’s byte length, throw a RangeError exception.
- %firstDescriptor の`~buffer$pD ~SET ~NOABRUPT `TransferArrayBuffer$A( %firstDescriptor の`~buffer$pD ) ◎ Set firstDescriptor’s buffer to ! TransferArrayBuffer(firstDescriptor’s buffer).
- ~ABRUPT `ReadableByteStreamControllerRespondInternal$A( %controller, %bytesWritten ) ◎ Perform ? ReadableByteStreamControllerRespondInternal(controller, bytesWritten).
`ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor) performs the following steps:
- ~Assert: `剰余$( %firstDescriptor の`埋まった~byte数$pD, %firstDescriptor の`要素~size$pD ) ~EQ 0 ◎ Assert: the remainder after dividing firstDescriptor’s bytes filled by firstDescriptor’s element size is 0.
- ~IF[ %firstDescriptor の`読取器~型$pD ~EQ `none^l ] ⇒ ~NOABRUPT `ReadableByteStreamControllerShiftPendingPullInto$A( %controller ) ◎ If firstDescriptor’s reader type is "none", perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).
- %stream ~LET %controller.`stream$rbsC ◎ Let stream be controller.[[stream]].
-
~IF[ ~NOABRUPT `ReadableStreamHasBYOBReader$A( %stream ) ~EQ ~T ]: ◎ If ! ReadableStreamHasBYOBReader(stream) is true,
-
~WHILE[ ~NOABRUPT `ReadableStreamGetNumReadIntoRequests$A( %stream ) ~GT 0 ]: ◎ While ! ReadableStreamGetNumReadIntoRequests(stream) > 0,
- %pullIntoDescriptor ~LET ~NOABRUPT `ReadableByteStreamControllerShiftPendingPullInto$A( %controller ) ◎ Let pullIntoDescriptor be ! ReadableByteStreamControllerShiftPendingPullInto(controller).
- ~NOABRUPT `ReadableByteStreamControllerCommitPullIntoDescriptor$A( %stream, %pullIntoDescriptor) ◎ Perform ! ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor).
-
`ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, pullIntoDescriptor)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, pullIntoDescriptor) performs the following steps:
- ~Assert: ( %pullIntoDescriptor の`埋まった~byte数$pD ~PLUS %bytesWritten ) ~LTE %pullIntoDescriptor の`~byte長さ$pD ◎ Assert: pullIntoDescriptor’s bytes filled + bytesWritten ≤ pullIntoDescriptor’s byte length.
- ~NOABRUPT `ReadableByteStreamControllerFillHeadPullIntoDescriptor$A( %controller, %bytesWritten, %pullIntoDescriptor ) ◎ Perform ! ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesWritten, pullIntoDescriptor).
-
~IF[ %pullIntoDescriptor の`読取器~型$pD ~EQ `none^l ]: ◎ If pullIntoDescriptor’s reader type is "none",
- ~ABRUPT `ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue$A( %controller, %pullIntoDescriptor ) ◎ Perform ? ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(controller, pullIntoDescriptor).
- ~NOABRUPT `ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue$A( %controller ) ◎ Perform ! ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
- ~RET ◎ Return.
-
~IF[ %pullIntoDescriptor の`埋まった~byte数$pD ~LT %pullIntoDescriptor の`最小な埋n$pD ] ⇒ ~RET ◎ If pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s minimum fill, return.
注記: `read()$byob 要請~用の記述子【 %pullIntoDescriptor 】は、 まだ その最小~長さまで埋まってない間は,当の~queueを成す頭部に居続けることになる — なので、 `下層~source$は,それを埋め続けれる。 ◎ A descriptor for a read() request that is not yet filled up to its minimum length will stay at the head of the queue, so the underlying source can keep filling it.
- ~NOABRUPT `ReadableByteStreamControllerShiftPendingPullInto$A( %controller ) ◎ Perform ! ReadableByteStreamControllerShiftPendingPullInto(controller).
- %remainderSize ~LET `剰余$( %pullIntoDescriptor の`埋まった~byte数$pD, %pullIntoDescriptor の`要素~size$pD ) ◎ Let remainderSize be the remainder after dividing pullIntoDescriptor’s bytes filled by pullIntoDescriptor’s element size.
-
~IF[ %remainderSize ~GT 0 ]: ◎ If remainderSize > 0,
- %end ~LET ( %pullIntoDescriptor の`~byte~offset$pD ~PLUS %pullIntoDescriptor の`埋まった~byte数$pD ) ◎ Let end be pullIntoDescriptor’s byte offset + pullIntoDescriptor’s bytes filled.
- ~ABRUPT `ReadableByteStreamControllerEnqueueClonedChunkToQueue$A( %controller, %pullIntoDescriptor の`~buffer$pD, %end ~MINUS %remainderSize, %remainderSize ) ◎ Perform ? ReadableByteStreamControllerEnqueueClonedChunkToQueue(controller, pullIntoDescriptor’s buffer, end − remainderSize, remainderSize).
- %pullIntoDescriptor の`埋まった~byte数$pD ~DECBY %remainderSize ◎ Set pullIntoDescriptor’s bytes filled to pullIntoDescriptor’s bytes filled − remainderSize.
- ~NOABRUPT `ReadableByteStreamControllerCommitPullIntoDescriptor$A( %controller.`stream$rbsC, %pullIntoDescriptor ) ◎ Perform ! ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]], pullIntoDescriptor).
- ~NOABRUPT `ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue$A( %controller ) ◎ Perform ! ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller).
`ReadableByteStreamControllerRespondInternal(controller, bytesWritten)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerRespondInternal(controller, bytesWritten) performs the following steps:
- %firstDescriptor ~LET %controller.`pendingPullIntos$rbsC[0] ◎ Let firstDescriptor be controller.[[pendingPullIntos]][0].
- ~Assert: ~NOABRUPT `CanTransferArrayBuffer$A( %firstDescriptor の`~buffer$pD ) ~EQ ~T ◎ Assert: ! CanTransferArrayBuffer(firstDescriptor’s buffer) is true.
- ~NOABRUPT `ReadableByteStreamControllerInvalidateBYOBRequest$A( %controller ) ◎ Perform ! ReadableByteStreamControllerInvalidateBYOBRequest(controller).
- %state ~LET %controller.`stream$rbsC.`state$rS ◎ Let state be controller.[[stream]].[[state]].
-
~IF[ %state ~EQ `closed^l ]: ◎ If state is "closed",
- ~Assert: %bytesWritten ~EQ 0 ◎ Assert: bytesWritten is 0.
- ~NOABRUPT `ReadableByteStreamControllerRespondInClosedState$A( %controller, %firstDescriptor ) ◎ Perform ! ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor).
-
~ELSE: ◎ Otherwise,
- ~Assert: %state ~EQ `readable^l ◎ Assert: state is "readable".
- ~Assert: %bytesWritten ~GT 0 ◎ Assert: bytesWritten > 0.
- ~ABRUPT `ReadableByteStreamControllerRespondInReadableState$A( %controller, %bytesWritten, %firstDescriptor ) ◎ Perform ? ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, firstDescriptor).
- ~NOABRUPT `ReadableByteStreamControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
`ReadableByteStreamControllerRespondWithNewView(controller, view)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerRespondWithNewView(controller, view) performs the following steps:
- ~Assert: %controller.`pendingPullIntos$rbsC は`空$でない ◎ Assert: controller.[[pendingPullIntos]] is not empty.
- ~Assert: ~NOABRUPT `IsDetachedBuffer$Ax( %view.`ViewedArrayBuffer^sl ) ~EQ F ◎ Assert: ! IsDetachedBuffer(view.[[ViewedArrayBuffer]]) is false.
- %firstDescriptor ~LET %controller.`pendingPullIntos$rbsC[0] ◎ Let firstDescriptor be controller.[[pendingPullIntos]][0].
- %state ~LET %controller.`stream$rbsC.`state$rS ◎ Let state be controller.[[stream]].[[state]].
-
~IF[ %state ~EQ `closed^l ]: ◎ If state is "closed",
- ~IF[ %view.`ByteLength^sl ~NEQ 0 ] ⇒ ~THROW `TypeError$jE ◎ If view.[[ByteLength]] is not 0, throw a TypeError exception.
-
~ELSE: ◎ Otherwise,
- ~Assert: %state ~EQ `readable^l ◎ Assert: state is "readable".
- ~IF[ %view.`ByteLength^sl ~EQ 0 ] ⇒ ~THROW `TypeError$jE ◎ If view.[[ByteLength]] is 0, throw a TypeError exception.
- ~IF[ ( %firstDescriptor の`~byte~offset$pD ~PLUS %firstDescriptor の`埋まった~byte数$pD ) ~NEQ %view.`ByteOffset^sl ] ⇒ ~THROW `RangeError$E ◎ If firstDescriptor’s byte offset + firstDescriptor’ bytes filled is not view.[[ByteOffset]], throw a RangeError exception.
- ~IF[ %firstDescriptor の`~buffer~byte長さ$pD ~NEQ %view.`ViewedArrayBuffer^sl.`ByteLength^sl ] ⇒ ~THROW `RangeError$E ◎ If firstDescriptor’s buffer byte length is not view.[[ViewedArrayBuffer]].[[ByteLength]], throw a RangeError exception.
- ~IF[ %firstDescriptor の`埋まった~byte数$pD ~PLUS %view.`ByteLength^sl ~GT %firstDescriptor の`~byte長さ$pD ] ⇒ ~THROW `RangeError$E ◎ If firstDescriptor’s bytes filled + view.[[ByteLength]] > firstDescriptor’s byte length, throw a RangeError exception.
- %viewByteLength ~LET %view.`ByteLength^sl ◎ Let viewByteLength be view.[[ByteLength]].
- %firstDescriptor の`~buffer$pD ~SET ~ABRUPT `TransferArrayBuffer$A( %view.`ViewedArrayBuffer^sl ) ◎ Set firstDescriptor’s buffer to ? TransferArrayBuffer(view.[[ViewedArrayBuffer]]).
- ~ABRUPT `ReadableByteStreamControllerRespondInternal$A( %controller, %viewByteLength ) ◎ Perform ? ReadableByteStreamControllerRespondInternal(controller, viewByteLength).
`ReadableByteStreamControllerShiftPendingPullInto(controller)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerShiftPendingPullInto(controller) performs the following steps:
- ~Assert: %controller.`byobRequest$rbsC ~EQ ~NULL ◎ Assert: controller.[[byobRequest]] is null.
- %descriptor ~LET %controller.`pendingPullIntos$rbsC[0] ◎ Let descriptor be controller.[[pendingPullIntos]][0].
- %controller.`pendingPullIntos$rbsC から %descriptor を`除去する$ ◎ Remove descriptor from controller.[[pendingPullIntos]].
- ~RET %descriptor ◎ Return descriptor.
`ReadableByteStreamControllerShouldCallPull(controller)@A は、次の手続きを遂行する: ◎ ReadableByteStreamControllerShouldCallPull(controller) performs the following steps:
- %stream ~LET %controller.`stream$rbsC ◎ Let stream be controller.[[stream]].
- ~IF[ %stream.`state$rS ~NEQ `readable^l ] ⇒ ~RET ~F ◎ If stream.[[state]] is not "readable", return false.
- ~IF[ %controller.`closeRequested$rbsC ~EQ ~T ] ⇒ ~RET ~F ◎ If controller.[[closeRequested]] is true, return false.
- ~IF[ %controller.`started$rbsC ~EQ ~F ] ⇒ ~RET ~F ◎ If controller.[[started]] is false, return false.
- ~IF[ ~NOABRUPT `ReadableStreamHasDefaultReader$A( %stream ) ~EQ ~T ]~AND[ ~NOABRUPT `ReadableStreamGetNumReadRequests$A( %stream ) ~GT 0 ] ⇒ ~RET ~T ◎ If ! ReadableStreamHasDefaultReader(stream) is true and ! ReadableStreamGetNumReadRequests(stream) > 0, return true.
- ~IF[ ~NOABRUPT `ReadableStreamHasBYOBReader$A( %stream ) ~EQ ~T ]~AND[ ~NOABRUPT `ReadableStreamGetNumReadIntoRequests$A( %stream ) ~GT 0 ] ⇒ ~RET ~T ◎ If ! ReadableStreamHasBYOBReader(stream) is true and ! ReadableStreamGetNumReadIntoRequests(stream) > 0, return true.
- %desiredSize ~LET ~NOABRUPT `ReadableByteStreamControllerGetDesiredSize$A( %controller ) ◎ Let desiredSize be ! ReadableByteStreamControllerGetDesiredSize(controller).
- ~Assert: %desiredSize ~NEQ ~NULL ◎ Assert: desiredSize is not null.
- ~IF[ %desiredSize ~GT 0 ] ⇒ ~RET ~T ◎ If desiredSize > 0, return true.
- ~RET ~F ◎ Return false.
`SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, autoAllocateChunkSize)@A は、次の手続きを遂行する: ◎ SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, autoAllocateChunkSize) performs the following steps:
- ~Assert: %stream.`controller$rS ~EQ `undefined^jv ◎ Assert: stream.[[controller]] is undefined.
-
~IF[ %autoAllocateChunkSize ~NEQ `undefined^jv ]: ◎ If autoAllocateChunkSize is not undefined,
- ~Assert: ~NOABRUPT `IsInteger$Ax( %autoAllocateChunkSize ) ~EQ ~T ◎ Assert: ! IsInteger(autoAllocateChunkSize) is true.
- ~Assert: %autoAllocateChunkSize ~GT 0 ◎ Assert: autoAllocateChunkSize is positive.
- %controller の ⇒# .`stream$rbsC ~SET %stream .`pullAgain$rbsC ~SET ~F, .`pulling$rbsC ~SET ~F, .`byobRequest$rbsC ~SET ~NULL ◎ Set controller.[[stream]] to stream. ◎ Set controller.[[pullAgain]] and controller.[[pulling]] to false. ◎ Set controller.[[byobRequest]] to null.
- ~NOABRUPT `ResetQueue$A( %controller ) ◎ Perform ! ResetQueue(controller).
- %controller の ⇒# .`closeRequested$rbsC ~SET ~F, .`started$rbsC ~SET ~F, .`strategyHWM$rbsC ~SET %highWaterMark, .`pullAlgorithm$rbsC ~SET %pullAlgorithm, .`cancelAlgorithm$rbsC ~SET %cancelAlgorithm, .`autoAllocateChunkSize$rbsC ~SET %autoAllocateChunkSize, .`pendingPullIntos$rbsC ~SET 新たな空`~list$ ◎ Set controller.[[closeRequested]] and controller.[[started]] to false. ◎ Set controller.[[strategyHWM]] to 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.`controller$rS ~SET %controller ◎ Set stream.[[controller]] to controller.
- %startResult ~LET %startAlgorithm() ◎ Let startResult be the result of performing startAlgorithm.
-
%startPromise ~LET `解決される~promise$( %startResult ) ◎ Let startPromise be a promise resolved with startResult.
-
%startPromise の`充足-時$には: ◎ Upon fulfillment of startPromise,
- %controller.`started$rbsC ~SET ~T ◎ Set controller.[[started]] to true.
- ~Assert: %controller.`pulling$rbsC ~EQ ~F ◎ Assert: controller.[[pulling]] is false.
- ~Assert: %controller.`pullAgain$rbsC ~EQ ~F ◎ Assert: controller.[[pullAgain]] is false.
- ~NOABRUPT `ReadableByteStreamControllerCallPullIfNeeded$A( %controller ) ◎ Perform ! ReadableByteStreamControllerCallPullIfNeeded(controller).
-
事由 %r による %startPromise の`却下-時$には: ◎ Upon rejection of startPromise with reason r,
- ~NOABRUPT `ReadableByteStreamControllerError$A( %controller, %r ) ◎ Perform ! ReadableByteStreamControllerError(controller, r).
-
`SetUpReadableByteStreamControllerFromUnderlyingSource(stream, underlyingSource, underlyingSourceDict, highWaterMark)@A は、次の手続きを遂行する: ◎ SetUpReadableByteStreamControllerFromUnderlyingSource(stream, underlyingSource, underlyingSourceDict, highWaterMark) performs the following steps:
- %controller ~LET `新たな$ `ReadableByteStreamController$I ◎ Let controller be a new ReadableByteStreamController.
- %startAlgorithm ~LET 次を走らす~algo ⇒ ~RET `undefined^jv ◎ Let startAlgorithm be an algorithm that returns undefined.
- %pullAlgorithm ~LET 次を走らす~algo ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ Let pullAlgorithm be an algorithm that returns a promise resolved with undefined.
- %cancelAlgorithm ~LET 次を走らす~algo ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ Let cancelAlgorithm be an algorithm that returns a promise resolved with undefined.
- ~IF[ %underlyingSourceDict[ "`start$usc" ] ~NEQ ε ] ⇒ %startAlgorithm ~SET 次を走らす~algo ⇒ ~RET `~callback関数を呼出す$( %underlyingSourceDict[ "`start$usc" ], « %controller »【, `投出し直す^i ?】, %underlyingSource ) ◎ If underlyingSourceDict["start"] exists, then set startAlgorithm to an algorithm which returns the result of invoking underlyingSourceDict["start"] with argument list « controller » and callback this value underlyingSource.
- ~IF[ %underlyingSourceDict[ "`pull$usc" ] ~NEQ ε ] ⇒ %pullAlgorithm ~SET 次を走らす~algo ⇒ ~RET `~callback関数を呼出す$( %underlyingSourceDict[ "`pull$usc" ], « %controller », ε, %underlyingSource ) ◎ If underlyingSourceDict["pull"] exists, then set pullAlgorithm to an algorithm which returns the result of invoking underlyingSourceDict["pull"] with argument list « controller » and callback this value underlyingSource.
- ~IF[ %underlyingSourceDict[ "`cancel$usc" ] ~NEQ ε ] ⇒ %cancelAlgorithm ~SET 所与の ( %reason ) に対し,次を走らす~algo ⇒ ~RET `~callback関数を呼出す$( %underlyingSourceDict[ "`cancel$usc" ], « %reason », ε, %underlyingSource ) ◎ If underlyingSourceDict["cancel"] exists, then set cancelAlgorithm to an algorithm which takes an argument reason and returns the result of invoking underlyingSourceDict["cancel"] with argument list « reason » and callback this value underlyingSource.
- %autoAllocateChunkSize ~LET %underlyingSourceDict[ "`autoAllocateChunkSize$usc" ] ◎ Let autoAllocateChunkSize be underlyingSourceDict["autoAllocateChunkSize"], if it exists,\
- ~IF[ %autoAllocateChunkSize ~EQ ε ] ⇒ %autoAllocateChunkSize ~SET `undefined^jv ◎ or undefined otherwise.
- ~IF[ %autoAllocateChunkSize ~EQ 0 ] ⇒ ~THROW `TypeError$jE ◎ If autoAllocateChunkSize is 0, then throw a TypeError exception.
- ~ABRUPT `SetUpReadableByteStreamController$A( %stream, %controller, %startAlgorithm, %pullAlgorithm, %cancelAlgorithm, %highWaterMark, %autoAllocateChunkSize ) ◎ Perform ? SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, autoAllocateChunkSize).
5. 可書~stream
5.1. 可書~streamの利用-法
`可読~stream$へ書込む通例の仕方は、 単純に,可読~streamをそれに`~pipeする$ことである。 これにより、 その`背圧$が尊重されるようになる — 可書~streamの`下層~sink$が,可読~streamが生産できるほど高速に~dataを受容できない場合に、 可読~streamにその旨が伝わり,その~data生産を減速させる機会cを得られるようになる。 ◎ 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【!All data successfully written!】)) .catch(%e => console.error(`何かまずいことが起きたようです^l【!Something went wrong!】, %e));
`書込器$を獲得して,その[ `write()$dw / `close()$dw ]~methodを利用すれば、 可書~streamに直に書込むこともできる。 それらは、[ 流入ng書込nを,~queueした上で`下層~sink$へ順に回送する ]ことを内部的に手入れするので、 手間をかけず無差別的に,可書~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【!i am a chunk of data】) .then(() => console.log(`~chunkは成功裡に書込まれました^l【!chunk successfully written!】)) .catch(%e => console.error(%e));
“成功” が何を意味するかは、 所与の~stream~instance(より精確には, その`下層~sink$)が裁定する。 例えば,~file~streamに対してなら、 単純に~OSが書込nを受容したことを意味し, `~chunk$を~diskへ書出すことは必要yでないであろう。 そのような通達を与える~~能が全くない~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からの流れ制御の通達に より精確に応答して, ~memoryの使用量を~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
を `await^c するので十分なので。
◎
Purposefully don't await; awaiting writer.ready is enough.
*/
%writer.write(%bytes).catch(() => {});
}
}
writeRandomBytesForever(myWritableStream).catch(
e => console.error(`何か不具合が生じたようです^l【!Something broke】, e)
);
`write()$dw から返される~promiseを `await^c していないことに注意 — それは、 `ready$dw ~promiseを `await^c するのと~~重複するので。 加えて,`以前の例@#example-manual-write-batch$と同様に、 `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$I ~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
]になったとき,充足されることに注意
— それは,書込nが成功する前になるかもしれない
(とりわけ、`限界水位$が高い事例では)。
◎
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$内には,書込nは決して~queueしておかれない代わりに、 以前の書込nが成功した後に限り,書込nを実行する ]ことを意味する — その結果、 単位時間あたりの流量は低下し得る。 ◎ 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.
5.2. `WritableStream^I ~class
`WritableStream$I は、 `可書~stream$を表現する。 ◎ The WritableStream represents a writable stream.
5.2.1. ~interface定義
`WritableStream$I ~class用の~Web~IDL定義は: ◎ The Web IDL definition for the WritableStream class is given as follows:
[`Exposed$=*, `Transferable$] interface `WritableStream@I { `WritableStream$mc(optional `object$ %underlyingSink, optional `QueuingStrategy$I %strategy = {}); readonly attribute `boolean$ `locked$ws; `Promise$<`undefined$> `abort$ws(optional `any$ %reason); `Promise$<`undefined$> `close$ws(); `WritableStreamDefaultWriter$I `getWriter$ws(); };
5.2.2. 内部~slot
`WritableStream$I の各~instanceは、 次に挙げる内部~slotを伴って作成される — 各項に与える記述は`規範的でない^em: ◎ Instances of WritableStream are created with the internal slots described in the following table: ◎ Internal Slot|Description (non-normative)
- `backpressure@wS
- 真偽値 ◎ A boolean\
- 制御器により設定される背圧~通達を指示する。 ◎ indicating the backpressure signal set by the controller
- `closeRequest@wS
- 書込器の `close()$dw ~methodから返される~promise ◎ The promise returned from the writer’s close() method
- `controller@wS
- ある `WritableStreamDefaultController$I ◎ A WritableStreamDefaultController\
- この~streamの状態と~queueを制御する能を伴って作成される。 ◎ created with the ability to control the state and queue of this stream
- `Detached@wS
- 真偽-~flag ◎ A boolean flag\
- この~streamが転送されたとき, ~T に設定される。 ◎ set to true when the stream is transferred
- `inFlightWriteRequest@wS
- `undefined^jv / ある~promise ◎ ↓
- `下層~sink$の書込n~algoが まだ実行-中で充足されていない間は、 現在の `in-flight^en な【“~~処理中にある”】書込n演算~用の~promiseに設定される。 ◎ 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,\
- これは、 再入~callを防止するために利用される。 ◎ used to prevent reentrant calls
- `inFlightCloseRequest@wS
- `undefined^jv / ある~promise ◎ ↓
- `下層~sink$の `close()^m ~methodが まだ~実行-中で~充足されていない間は、 現在の `in-flight^en な~close~algo用の~promiseに設定される。 ◎ 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,\
- これは、[ `abort()$dw ~methodにより~closeが中断される ]のを防止するために利用される。 ◎ used to prevent the abort() method from interrupting close
- `pendingAbortRequest@wS
- `処理待ち中止-要請$ ◎ A pending abort request
- `state@wS
- 文字列 ◎ A string\
- 内部的に利用される,~streamの現在の状態 — 次に挙げるいずれかになる ⇒# `writable^l, `closed^l, `erroring^l, `errored^l ◎ containing the stream’s current state, used internally; one of "writable", "closed", "erroring", or "errored"
- `storedError@wS
- この~streamが どう失敗したかを指示する値 ◎ A value indicating how the stream failed,\
- `errored^l 状態にある~streamに対し演算するよう試行しているとき, 失敗~事由か例外として与えられることになる。 ◎ to be given as a failure reason or exception when trying to operate on the stream while in the "errored" state
- `writer@wS
- `undefined^jv / ある `WritableStreamDefaultWriter$I ◎ A WritableStreamDefaultWriter instance,\
- この~streamを`~lock$している`書込器$は[ 在るならば それ/ 無いならば `undefined^jv ]になる。 ◎ if the stream is locked to a writer, or undefined if it is not
- `writeRequests@wS
- ~promiseたちが成す`~list$ ◎ A list of promises\
- `下層~sink$がまだ処理していない書込n要請たちが成す[ この~streamの内部~queue ]を表現する。 ◎ representing the stream’s internal queue of write requests not yet processed by the underlying sink
注記: [ `inFlightCloseRequest$wS ~slot, `closeRequest$wS ~slot ]は、 互いに排他的である。 また、[ `inFlightWriteRequest$wS ~NEQ `undefined^jv ]の間に `writeRequests$wS から要素が除去されることはない。 実装は、 これらの不変則に基づいて,これらの~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.
`処理待ち中止-要請@ は、 次に挙げる`~item$sctからなる`構造体$であり, ~streamを中止する要請を その処理に入るまで追跡するために利用される: ◎ A pending abort request is a struct used to track a request to abort the stream before that request is finally processed. It has the following items:
- `~promise@aR ◎ promise
- `WritableStreamAbort()$A から返された~promise。 ◎ A promise returned from WritableStreamAbort
- `事由@aR ◎ reason
- 中止-事由として `WritableStreamAbort()$A に渡された~JS値 ◎ A JavaScript value that was passed as the abort reason to WritableStreamAbort
- `すでに~errorしたか@aR ◎ was already erroring
- 真偽値 ◎ A boolean\
- `WritableStreamAbort()$A を~callした時点で、 当の~streamは `erroring^l 状態にあったかどうかを指示する — それは、 中止-要請の成り行きに影響iする。 ◎ indicating whether or not the stream was in the "erroring" state when WritableStreamAbort was called, which impacts the outcome of the abort request
5.2.3. 下層~sink~API
`new WritableStream()$m 構築子は、 1 個目の引数に[ `下層~sink$を表現している~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:
dictionary `UnderlyingSink@I { `UnderlyingSinkStartCallback$I `start$usk; `UnderlyingSinkWriteCallback$I `write$usk; `UnderlyingSinkCloseCallback$I `close$usk; `UnderlyingSinkAbortCallback$I `abort$usk; `any$ `type$usk; }; callback `UnderlyingSinkStartCallback@I = `any$ (`WritableStreamDefaultController$I %controller); callback `UnderlyingSinkWriteCallback@I = `Promise$<`undefined$> (`any$ %chunk, `WritableStreamDefaultController$I %controller); callback `UnderlyingSinkCloseCallback@I = `Promise$<`undefined$> (); callback `UnderlyingSinkAbortCallback@I = `Promise$<`undefined$> (optional `any$ %reason);
- `start(controller)@usk ( `UnderlyingSinkStartCallback$I 型) ◎ start(controller), of type UnderlyingSinkStartCallback
- この関数は、 `WritableStream$I を作成する間に即時に~callされる。 ◎ A function that is called immediately during creation of the WritableStream.
- これは概して、 資源が表現されている`下層~sink$への~accessを獲得するために利用される。 ◎ Typically this is used to acquire access to the underlying sink resource being represented.
- ここで何かを設定しておく処理nが非同期的になる場合、 この関数は,成否を通達する~promiseを返すようにすることもできる ⇒# 却下される~promiseは、~streamを~errorにすることになる。 投出された例外は、 `new WritableStream()$m 構築子により投出し直されることになる。 ◎ 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)@usk ( `UnderlyingSinkWriteCallback$I 型) ◎ write(chunk, controller), of type UnderlyingSinkWriteCallback
- この関数は、[ `下層~sink$へ書込まれる~dataを成す,新たな`~chunk$ ]が準備済みになったときに~callされる。 ~stream実装は、 次を保証する ⇒ この関数は、 以前の書込nが成功した後に限り~callされ,[ `start()$usk が成功する前 /[ `close()$usk / `abort()$usk ]が~callされた後 ]には決して~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.
- この関数は、 `下層~sink$により呈示される資源に,実際に~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を書込む処理nが非同期的になる場合、
この関数は
— ~API利用者に成否の通達を通信するために —
成否を通達する~promiseを返すようにすることもでき、
返された~promiseは,
%writer.`write()$dw
の~call元へ — それが個々の書込nを監視できるよう — 通信されることになる。 例外を投出した場合、 却下される~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$sec, `背圧や成功の通達を伴う可書~stream$sec ◎ Note that such signals are not always available; compare e.g. § 10.6 A writable stream with no backpressure or success signals with § 10.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を欲することを通達するために増やされるのは、 書込nが成功した場合に限られる。
-
- この関数から返され得る~promiseは、[ `きちんと挙動する@#write-mutable-chunks$`生産器$が,`~chunk$を — それが全部的に処理される前に — 変異させるよう試みない ]ことを確保するため利用される。 (仕様には、 これを保証する機構は無い — それは、 `生産器$と`下層~sink$の間における非正式な契約である。) ◎ Finally, the promise potentially returned by this function is used to ensure that well-behaved producers do not attempt to mutate the chunk before it has been fully processed. (This is not guaranteed by any specification machinery, but instead is an informal contract between producers and the underlying sink.)
- `close()@usk ( `UnderlyingSinkCloseCallback$I 型) ◎ close(), of type UnderlyingSinkCloseCallback
-
この関数は、
`生産器$が
%writer.`close()$dw
を介して,次を通達した後に~callされる ⇒ 生産器による,`~chunk$たちの~streamへの書込みは済み、 後続して,~queueしておかれた すべての書込nは成功裡に完了した ◎ 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. - 次のいずれかに必要yな動作があれば、 この関数~内で遂行できる ⇒# `下層~sink$への書込nを完結する/ `下層~sink$への書込nをどこかへ書出す/ 保持されている資源への~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処理nが非同期的になる場合、 この関数は,成否を通達する~promiseを返すようにすることもできる:
-
その結果は、
%writer.`close()$dw
~methodの返り値を介して,その~call元(生産器)へ通信されることになる。 - 加えて,却下される~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)@usk ( `UnderlyingSinkAbortCallback$I 型) ◎ abort(reason), of type UnderlyingSinkAbortCallback
-
この関数は、
`生産器$が[
~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()$usk とほぼ同様に — 片付けれるが、 たぶん何か~customな取扱いも伴われる。 ◎ This function can clean up any held resources, much like close(), but perhaps with some custom handling.
-
この~shutdown処理nが非同期的になる場合、
この関数は,成否を通達する~promiseを返すようにすることもできる
— その結果は、
%writer.`abort()$dw
~methodの返り値を介して,その~call元(生産器)へ通信されることになる。 例外を投出した場合、 却下される~promiseを返すのと同じに扱われる。 いずれにせよ、 ~streamは — 中止されたことを指示する,新たな `TypeError$jE で — ~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 writer.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. - `type@usk ( `any$I 型) ◎ type, of type any
- この~propは,将来の利用-用に予約されており、 値を給するどの試みに対しても,例外を投出することになる。 ◎ This property is reserved for future use, so any attempts to supply a value will throw an exception.
[ `start()$usk / `write()$usk ]に渡される %controller 引数は、 `WritableStreamDefaultController$I の~instanceであり, ~streamを~errorにする能を備える。 これは主に、 ~promiseに基づかない~APIと橋渡しするために利用される。 その例は、 `背圧や成功の通達を伴わない可書~stream$secに見れる。 ◎ 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 § 10.6 A writable stream with no backpressure or success signals.
5.2.4. 構築子/~method/~prop
- %stream = `new WritableStream(underlyingSink[, strategy])$m
- 供された`下層~sink$を包装している新たな `WritableStream$I を作成する。 %underlyingSink 引数についての詳細は、 `下層~sink~API$secを見よ。 ◎ Creates a new WritableStream wrapping the provided underlying sink. See § 5.2.3 The underlying sink API for more details on the underlyingSink argument.
- %strategy 引数は — `~queuing策~API$secにて述べるように — ~streamの`~queuing策$を表現する。 供されなかった場合の既定の挙動は、 `限界水位$ 1 にされた `CountQueuingStrategy$I と同じになる。 ◎ The strategy argument represents the stream’s queuing strategy, as described in § 7.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.
- %isLocked = %stream.`locked$ws
- 可書~streamが書込器に`~lockされて$いるかどうかを返す。 ◎ Returns whether or not the writable stream is locked to a writer.
- await %stream.`abort([ reason ])$ws
- ~streamを`中止する$。 それは、[ 生産器は,もはや成功裡に~streamに書込めない ]ことを通達する — 書込nが~queueしておかれたときは、 破棄した上で,即時に~error状態に移行することになる。 これはまた、 `下層~sink$の中止する仕組みも実行することになる。 ◎ 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.
- 返される~promiseは、[ ~streamは成功裡に~shut-downされた場合 ]には充足され,[ そうするときに~errorしたことが`下層~sink$から通達された場合 ]には却下されることになる。 加えて,当の~streamは現在`~lockされて$いる場合には、 `TypeError$jE で却下されることになる (当の~streamを取消すよう試みることなく)。 ◎ The returned promise will fulfill if the stream shuts down successfully, or reject if the underlying sink signaled that there was an error doing so. Additionally, it will reject with a TypeError (without attempting to cancel the stream) if the stream is currently locked.
- await %stream.`close()$ws
- ~streamを~closeする。 `下層~sink$は、 自身を~closeする挙動を呼出す前に, それまでに書込まれた`~chunk$を処理し終えることになる。 その間,更に書込もうとする試みは、 失敗することになる (~streamを~errorにすることなく)。 ◎ Closes the 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された場合 ]には充足され,[ この処理nの間に~errorに遭遇した場合 ]には却下される。 加えて,当の~streamは現在`~lockされて$いる場合には、 `TypeError$jE で却下されることになる (当の~streamを取消すよう試みることなく)。 ◎ The method returns a promise that will fulfill if all remaining chunks are successfully written and the stream successfully closes, or rejects if an error is encountered during this process. Additionally, it will reject with a TypeError (without attempting to cancel the stream) if the stream is currently locked.
- %writer = %stream.`getWriter()$ws
- `書込器$( `WritableStreamDefaultWriter$I の~instance)を作成して, ~streamをこの新たな書込器に`~lock$する。 ~streamが~lockされている間は、 他の書込器は,この~lockが`解放-$されるまで獲得できない。 ◎ 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.
- この機能性は、[ 他から中断されたり書込nが差挟まれることなく,~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.
`new WritableStream(underlyingSink, strategy)@m 構築子~手続きは: ◎ The new WritableStream(underlyingSink, strategy) constructor steps are:
- ~IF[ %underlyingSink ~EQ ε ] ⇒ %underlyingSink ~SET ~NULL ◎ If underlyingSink is missing, set it to null.
-
%underlyingSinkDict ~LET `~IDL値に変換する$( %underlyingSink, `UnderlyingSink$I ) ◎ Let underlyingSinkDict be underlyingSink, converted to an IDL value of type UnderlyingSink.
注記: %underlyingSink 引数を `UnderlyingSink$I 型として直に宣言できないのは、 元の~objへの参照が失われるからである。 ~obj上の各種~methodを`~methodを呼出せる$よう,~objは維持する必要がある。 ◎ We cannot declare the underlyingSink argument as having the UnderlyingSink type directly, because doing so would lose the reference to the original object. We need to retain the object so we can invoke the various methods on it.
-
~IF[ %underlyingSinkDict[ "`type$usk" ] ~NEQ ε ] ⇒ ~THROW `RangeError$E ◎ If underlyingSinkDict["type"] exists, throw a RangeError exception.
注記: これは、 将来に新たな型を[ 後方-互換性を懸念することなく,追加する ]ことを許容する。 ◎ This is to allow us to add new potential types in the future, without backward-compatibility concerns.
- ~NOABRUPT `InitializeWritableStream$A( コレ ) ◎ Perform ! InitializeWritableStream(this).
- %sizeAlgorithm ~LET ~ABRUPT `ExtractSizeAlgorithm$A( %strategy ) ◎ Let sizeAlgorithm be ! ExtractSizeAlgorithm(strategy).
- %highWaterMark ~LET ~ABRUPT `ExtractHighWaterMark$A( %strategy, 1 ) ◎ Let highWaterMark be ? ExtractHighWaterMark(strategy, 1).
- ~ABRUPT `SetUpWritableStreamDefaultControllerFromUnderlyingSink$A( コレ, %underlyingSink, %underlyingSinkDict, %highWaterMark, %sizeAlgorithm ) ◎ Perform ? SetUpWritableStreamDefaultControllerFromUnderlyingSink(this, underlyingSink, underlyingSinkDict, highWaterMark, sizeAlgorithm).
`locked@ws 取得子~手続きは: ◎ The locked getter steps are:
- ~RET ~NOABRUPT `IsWritableStreamLocked$A( コレ ) ◎ Return ! IsWritableStreamLocked(this).
`abort(reason)@ws ~method手続きは: ◎ The abort(reason) method steps are:
- ~IF[ ~NOABRUPT `IsWritableStreamLocked$A( コレ ) ~EQ ~T ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
- ~RET ~NOABRUPT `WritableStreamAbort$A( コレ, %reason ) ◎ Return ! WritableStreamAbort(this, reason).
`close()@ws ~method手続きは: ◎ The close() method steps are:
- ~IF[ ~NOABRUPT `IsWritableStreamLocked$A( コレ ) ~EQ ~T ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
- ~IF[ ~NOABRUPT `WritableStreamCloseQueuedOrInFlight$A( コレ ) ~EQ ~T ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If ! WritableStreamCloseQueuedOrInFlight(this) is true, return a promise rejected with a TypeError exception.
- ~RET ~NOABRUPT `WritableStreamClose$A( コレ ) ◎ Return ! WritableStreamClose(this).
`getWriter()@ws ~method手続きは: ◎ The getWriter() method steps are:
- ~RET ~ABRUPT `AcquireWritableStreamDefaultWriter$A( コレ ) ◎ Return ? AcquireWritableStreamDefaultWriter(this).
5.2.5. `postMessage()^m を介する転送
%destination.postMessage(%ws, { transfer: [%ws] });
- `WritableStream$I を別の[ ~frame/~window/~worker ]へ送信する。 ◎ Sends a WritableStream to another frame, window, or worker.
- 転送された~streamは、 元の~streamとまったく同じに利用できる。 以降、 元の~streamは`~lock$され,利用-不能になる。 ◎ The transferred stream can be used exactly like the original. The original will become locked and no longer directly usable.
`WritableStream$I ~objは、 `転送-可能$である: ◎ WritableStream objects are transferable objects.\
-
その`転送-手続き$は、 所与の ( %値, %~data保持体 ) に対し: ◎ Their transfer steps, given value and dataHolder, are:
- ~IF[ ~NOABRUPT `IsWritableStreamLocked$A( %値 ) ~EQ ~T ] ⇒ ~THROW `DataCloneError$E ◎ If ! IsWritableStreamLocked(value) is true, throw a "DataCloneError" DOMException.
- %port1 ~LET `現在の~realm$内の`新たな$ `MessagePort$I ◎ Let port1 be a new MessagePort in the current Realm.
- %port2 ~LET `現在の~realm$内の`新たな$ `MessagePort$I ◎ Let port2 be a new MessagePort in the current Realm.
- `~portを連絡する$( %port1, %port2 ) ◎ Entangle port1 and port2.
- %readable ~LET `現在の~realm$内の`新たな$ `ReadableStream$I ◎ Let readable be a new ReadableStream in the current Realm.
- ~NOABRUPT `SetUpCrossRealmTransformReadable$A( %readable, %port1 ) ◎ Perform ! SetUpCrossRealmTransformReadable(readable, port1).
- %promise ~LET ~NOABRUPT `ReadableStreamPipeTo$A( %readable, %値, ~F, ~F, ~F ) ◎ Let promise be ! ReadableStreamPipeTo(readable, value, false, false, false).
- %promise.`PromiseIsHandled^sl ~SET ~T ◎ Set promise.[[PromiseIsHandled]] to true.
- %~data保持体.`port^sl ~SET ~NOABRUPT `StructuredSerializeWithTransfer$A( %port2, « %port2 » ) ◎ Set dataHolder.[[port]] to ! StructuredSerializeWithTransfer(port2, « port2 »).
-
その`転送-受信-時の手続き$は、 所与の ( %~data保持体, %値 ) に対し: ◎ Their transfer-receiving steps, given dataHolder and value, are:
- %deserializedRecord ~LET ~NOABRUPT `StructuredDeserializeWithTransfer$A( %~data保持体.`port^sl, `現在の~realm$ ) ◎ Let deserializedRecord be ! StructuredDeserializeWithTransfer(dataHolder.[[port]], the current Realm).
- %port ~LET %deserializedRecord.`Deserialized^sl ◎ Let port be a deserializedRecord.[[Deserialized]].
- ~NOABRUPT `SetUpCrossRealmTransformWritable$A( %値, %port ) ◎ Perform ! SetUpCrossRealmTransformWritable(value, port).
5.3. `WritableStreamDefaultWriter^I ~class
`WritableStreamDefaultWriter$I ~classは、[ `WritableStream$I ~instanceから配給されるように設計された`可書~stream書込器$ ]を表現する。 ◎ The WritableStreamDefaultWriter class represents a writable stream writer designed to be vended by a WritableStream instance.
5.3.1. ~interface定義
`WritableStreamDefaultWriter$I ~class用の~Web~IDL定義は: ◎ The Web IDL definition for the WritableStreamDefaultWriter class is given as follows:
[`Exposed$=*] interface `WritableStreamDefaultWriter@I { `WritableStreamDefaultWriter$mc(`WritableStream$I %stream); readonly attribute `Promise$<`undefined$> `closed$dw; readonly attribute `unrestricted double$? `desiredSize$dw; readonly attribute `Promise$<`undefined$> `ready$dw; `Promise$<`undefined$> `abort$dw(optional `any$ %reason); `Promise$<`undefined$> `close$dw(); `undefined$ `releaseLock$dw(); `Promise$<`undefined$> `write$dw(optional `any$ %chunk); };
5.3.2. 内部~slot
`WritableStreamDefaultWriter$I の各~instanceは、 次に挙げる内部~slotを伴って作成される — 各項に与える記述は`規範的でない^em: ◎ Instances of WritableStreamDefaultWriter are created with the internal slots described in the following table: ◎ Internal Slot|Description (non-normative)
- `closedPromise@wsW
- この書込器の `closed$dw 取得子から返される~promise ◎ A promise returned by the writer’s closed getter
- `readyPromise@wsW
- この書込器の `ready$dw 取得子から返される~promise ◎ A promise returned by the writer’s ready getter
- `stream@wsW
- この書込器【!読取器】を所有する `WritableStream$I の~instance ◎ A WritableStream instance that owns this reader
5.3.3. 構築子/~method/~prop
- %writer = `new WritableStreamDefaultWriter(stream)$m
-
これは、
%stream.`getWriter()$ws
を~callすることと等価になる。 ◎ This is equivalent to calling stream.getWriter(). - await %writer.`closed$dw
- ~promiseを返す — それは、 ~streamが~closeされたときは充足され,[ どこかで~errorした / ~streamが~closeし終える前に書込器の~lockが`解放-$された ]ときは却下される。 ◎ 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.
- %desiredSize = %writer.`desiredSize$dw
- `~streamの内部~queueの残り~size$を返す。 ~queueを溢れている場合の結果は、 負になる。 `生産器$は、 書込む~dataの的確な量を決定するときに,この情報を利用できる。 ◎ 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しておくのが中止されたことに因り)、 ~NULL になる。 ~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. And the getter will throw an exception if invoked when the writer’s lock is released.
- await %writer.`ready$dw
- ~promiseを返す — それは、 `~streamの内部~queueの残り~size$が 0 以下から正へ遷移したときに充足され, `背圧$は もう適用されないことを通達することになる。 `~streamの内部~queueの残り~size$が再び 0 以下に落ち込んだときには、 取得子は,[ 次回の遷移まで処理待ちであり続ける,`新たな~promise$ ]を返すことになる。 ◎ 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 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.
- await %writer.`abort([ reason ])$dw
-
当の読取器は`作動中$である場合、
%stream.`abort(reason)$ws
と同じに挙動する。 ◎ If the reader is active, behaves the same as stream.abort(reason). - await %writer.`close()$dw
-
当の読取器は`作動中$である場合、
%stream.`close()$ws
と同じに挙動する。 ◎ If the reader is active, behaves the same as stream.close(). - %writer.`releaseLock()$dw
- 書込器による対応する~stream上の~lockを`解放-$する。 ~lockが解放されて以降は、 当の書込器は,もはや`作動中$でなくなる。 結付けられた~streamが,~lockが解放される時点で~error状態にある場合、 それ以降も,書込器はそれを引き継ぐように~errorしたように現れる。 他の場合、 書込器は~closeされたように現れる。 ◎ 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.
- まだ完遂してない進行中な書込nがあるときでも (すなわち、 前回の `write()$dw ~callから返された~promiseが決着していなくとも)、 ~lockは解放できることに注意。 書込n中に書込器に対する~lockを保持することは、 必要yでない — ~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.
- await %writer.`write(chunk)$dw
- 所与の`~chunk$を可書~streamに書込む — 以前の書込nがあれば それが成功裡に完遂するまで待機した上で,`下層~sink$の `write()$usk ~methodに`~chunk$を送信することにより。 この~methodは、 ~promiseを返す — それは、 書込nが成功したときは `undefined^jv で充足され,[ 書込nに失敗した場合/ 書込み処理nが起動される前に~streamが~errorした場合 ]は 却下される。 ◎ 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.
- “成功” が 何を意味するかは、 `下層~sink$に委ねられることに注意。 それは、 単純に`~chunk$が受容されたことを指示するだけかもしれない — それが最終~行先に安全に保存されることは、 必要yでない。 ◎ 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.
- %~chunk が変異-可能である場合、 `生産器$には,[ %~chunk を `write()$dw に渡してから, `write()$dw から返された~promiseが決着するまで ]は[ %~chunk を変異するのは避ける ]よう勧める。 これは、[ 当の`下層~sink$が受取って処理する値は、 渡されたものと同じになる ]ことを確保する。 ◎ If chunk is mutable, producers are advised to avoid mutating it after passing it to write(), until after the promise returned by write() settles. This ensures that the underlying sink receives and processes the same value that was passed in.
`new WritableStreamDefaultWriter(stream)@m 構築子~手続きは: ◎ The new WritableStreamDefaultWriter(stream) constructor steps are:
- ~ABRUPT `SetUpWritableStreamDefaultWriter$A( コレ, %stream ) ◎ Perform ? SetUpWritableStreamDefaultWriter(this, stream).
`closed@dw 取得子~手続きは: ◎ The closed getter steps are:
- ~RET コレ.`closedPromise$wsW ◎ Return this.[[closedPromise]].
`desiredSize@dw 取得子~手続きは: ◎ The desiredSize getter steps are:
- ~IF[ コレ.`stream$wsW ~EQ `undefined^jv ] ⇒ ~THROW `TypeError$jE ◎ If this.[[stream]] is undefined, throw a TypeError exception.
- ~RET ~NOABRUPT `WritableStreamDefaultWriterGetDesiredSize$A( コレ ) ◎ Return ! WritableStreamDefaultWriterGetDesiredSize(this).
`ready@dw 取得子~手続きは: ◎ The ready getter steps are:
- ~RET コレ.`readyPromise$wsW ◎ Return this.[[readyPromise]].
`abort(reason)@dw ~method手続きは: ◎ The abort(reason) method steps are:
- ~IF[ コレ.`stream$wsW ~EQ `undefined^jv ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.
- ~RET ~NOABRUPT `WritableStreamDefaultWriterAbort$A( コレ, %reason ) ◎ Return ! WritableStreamDefaultWriterAbort(this, reason).
`close()@dw ~method手続きは: ◎ The close() method steps are:
- %stream ~LET コレ.`stream$wsW ◎ Let stream be this.[[stream]].
- ~IF[ %stream ~EQ `undefined^jv ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If stream is undefined, return a promise rejected with a TypeError exception.
- ~IF[ ~NOABRUPT `WritableStreamCloseQueuedOrInFlight$A( %stream ) ~EQ ~T ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If ! WritableStreamCloseQueuedOrInFlight(stream) is true, return a promise rejected with a TypeError exception.
- ~RET ~NOABRUPT `WritableStreamDefaultWriterClose$A( コレ ) ◎ Return ! WritableStreamDefaultWriterClose(this).
`releaseLock()@dw ~method手続きは: ◎ The releaseLock() method steps are:
- %stream ~LET コレ.`stream$wsW ◎ Let stream be this.[[stream]].
- ~IF[ %stream ~EQ `undefined^jv ] ⇒ ~RET ◎ If stream is undefined, return.
- ~Assert: %stream.`writer$wS ~NEQ `undefined^jv ◎ Assert: stream.[[writer]] is not undefined.
- ~NOABRUPT `WritableStreamDefaultWriterRelease$A( コレ ) ◎ Perform ! WritableStreamDefaultWriterRelease(this).
`write(chunk)@dw ~method手続きは: ◎ The write(chunk) method steps are:
- ~IF[ コレ.`stream$wsW ~EQ `undefined^jv ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.
- ~RET ~NOABRUPT `WritableStreamDefaultWriterWrite$A( コレ, %chunk ) ◎ Return ! WritableStreamDefaultWriterWrite(this, chunk).
5.4. `WritableStreamDefaultController^I ~class
`WritableStreamDefaultController$I ~classは、 `WritableStream$I の状態の制御を許容する~methodたちを有する。 `WritableStream$I の構築-時には、 `下層~sink$には,操作するための対応する `WritableStreamDefaultController$I の~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.
5.4.1. ~interface定義
`WritableStreamDefaultController$I ~class用の~Web~IDL定義は: ◎ The Web IDL definition for the WritableStreamDefaultController class is given as follows:
[`Exposed$=*] interface `WritableStreamDefaultController@I { readonly attribute `AbortSignal$I `signal$wsdc; `undefined$ `error$wsdc(optional `any$ %e); };
5.4.2. 内部~slot
`WritableStreamDefaultController$I の各~instanceは、 次に挙げる内部~slotを伴って作成される — 各項に与える記述は`規範的でない^em: ◎ Instances of WritableStreamDefaultController are created with the internal slots described in the following table: ◎ Internal Slot|Description (non-normative)
- `abortAlgorithm@wsdC
- 1 個の引数(中止-事由)をとり,~promiseを返す~algo ◎ A promise-returning algorithm, taking one argument (the abort reason),\
- 要請された中止-を`下層~sink$へ通信する。 ◎ which communicates a requested abort to the underlying sink
- `abortController@wsdC
- ある `AbortController$I ◎ An AbortController\
- ~streamが`中止-$されたとき,処理待ちな[ 書込n/~close ]演算を中止するために利用され得る。 ◎ that can be used to abort the pending write or close operation when the stream is aborted.
- `closeAlgorithm@wsdC
- ~promiseを返す~algo ◎ A promise-returning algorithm\
- 要請された~closeを`下層~sink$へ通信する。 ◎ which communicates a requested close to the underlying sink
- `queue@wsdC
- ある`~list$ ◎ A list\
- ~streamの[ `~chunk$たちが成す内部~queue ]を表現する。 ◎ representing the stream’s internal queue of chunks
- `queueTotalSize@wsdC
- `queue$wsdC 内に格納されている すべての~chunkの合計~size (`個別~size付き~queue$secを見よ) ◎ The total size of all the chunks stored in [[queue]] (see § 8.1 Queue-with-sizes)
- `started@wsdC
- 真偽-~flag ◎ A boolean flag\
- 当の~streamの`下層~sink$が開始処理【 `start()$usk 】を完遂したかどうかを指示する。 ◎ indicating whether the underlying sink has finished starting
- `strategyHWM@wsdC
- ~number ◎ A number\
- 当の~streamの`~queuing策$の一部として,~streamの作成子から給され、 ~streamが その`下層~sink$に`背圧$を適用することになる~~基準を指示する。 ◎ 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@wsdC
- ある~algo ◎ An algorithm\
- 当の~streamの`~queuing策$の一部として,~streamの作成子から給され、 ~enqueueされた`~chunk$たちの~sizeを計算する。 ◎ to calculate the size of enqueued chunks, as part of the stream’s queuing strategy
- `stream@wsdC
- ある `WritableStream$I ◎ ↓
- この制御器により制御される`可書~stream$。 ◎ The WritableStream instance controlled
- `writeAlgorithm@wsdC
- 1 個の引数(書込む~chunk)をとり,~promiseを返す~algo ◎ A promise-returning algorithm, taking one argument (the chunk to write),\
- `下層~sink$に~dataを書込む。 ◎ which writes data to the underlying sink
`~close~sentinel@i ( `close sentinel^en )は、 ~streamは~closeされたことを通達する一意な値であり, `~chunk$に代えて `queue$wsdC の中に~enqueueされる。 それは、 内部に限り利用され,~web開発者に公開されることは決してない。 ◎ The close sentinel is a unique value enqueued into [[queue]], in lieu of a chunk, to signal that the stream is closed. It is only used internally, and is never exposed to web developers.
5.4.3. ~methodと~prop
- %controller.`signal$wsdc
- ~streamが`中止-$されたとき,処理待ちな[ 書込n/~close ]演算を中止するために利用できる `AbortSignal$I 。 ◎ An AbortSignal that can be used to abort the pending write or close operation when the stream is aborted.
- %controller.`error(e)$wsdc
- 制御先の可書~streamを~closeする — 以降のヤリトリは、 すべて所与の~error %e で失敗させる。 ◎ Closes the controlled writable stream, making all future interactions with it fail with the given error e.
- この~methodは、 稀にしか利用されない — 通例的には、[ `下層~sink$のいずれかの~methodから,却下される~promiseを返す ]だけで足りるので。 しかしながら、[ `下層~sink$とのヤリトリによる通常の~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.
`error(e)@wsdc ~method手続きは: ◎ The error(e) method steps are:
- %state ~LET コレ.`stream$wsdC.`state$wS ◎ Let state be this.[[stream]].[[state]].
- ~IF[ %state ~NEQ `writable^l ] ⇒ ~RET ◎ If state is not "writable", return.
- ~NOABRUPT `WritableStreamDefaultControllerError$A( コレ, %e ) ◎ Perform ! WritableStreamDefaultControllerError(this, e).
5.4.4. 内部~method
各 `WritableStreamDefaultController$I ~instanceは、 以下に与える内部~methodを実装する。 可書~stream実装は、 これらの中へ~callすることになる。 ◎ The following are internal methods implemented by each WritableStreamDefaultController instance. The writable stream implementation will call into these.
注記: これらが抽象-演算ではなく,~methodの形をとる理由は、 可書~stream実装が制御器~実装から切り離され, 将来には他の制御器でも — それらが,これらの内部~methodを実装するならば — 拡げれることを明瞭にするためである。 同様の経緯は,可読~streamにも見られ(`制御器との~interface法$secを見よ)、 そこでは,[ 各種 内部~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 (see § 4.9.2 Interfacing with controllers), where there actually are multiple controller types and as such the counterpart internal methods are used polymorphically.
`[[AbortSteps]]( reason )@wsdc は、 `AbortSteps$sl の契約を実装する。 それは、次の手続きを遂行する: ◎ [[AbortSteps]](reason) implements the [[AbortSteps]] contract. It performs the following steps:
- %result ~LET コレ.`abortAlgorithm$wsdC( %reason ) ◎ Let result be the result of performing this.[[abortAlgorithm]], passing reason.
- ~NOABRUPT `WritableStreamDefaultControllerClearAlgorithms$A( コレ ) ◎ Perform ! WritableStreamDefaultControllerClearAlgorithms(this).
- ~RET %result ◎ Return result.
`[[ErrorSteps]]()@wsdc は `ErrorSteps$sl の契約を実装する。 それは、次の手続きを遂行する: ◎ [[ErrorSteps]]() implements the [[ErrorSteps]] contract. It performs the following steps:
- ~NOABRUPT `ResetQueue$A( コレ ) ◎ Perform ! ResetQueue(this).
5.5. 抽象-演算
5.5.1. 可書~streamとの作業-法
以下に与える抽象-演算は、 `WritableStream$I ~instanceに対し高~levelから演算する。 ◎ The following abstract operations operate on WritableStream instances at a higher level.
`AcquireWritableStreamDefaultWriter(stream)@A は、次の手続きを遂行する: ◎ AcquireWritableStreamDefaultWriter(stream) performs the following steps:
- %writer ~LET `新たな$ `WritableStreamDefaultWriter$I ◎ Let writer be a new WritableStreamDefaultWriter.
- ~ABRUPT `SetUpWritableStreamDefaultWriter$A( %writer, %stream ) ◎ Perform ? SetUpWritableStreamDefaultWriter(writer, stream).
- ~RET %writer ◎ Return writer.
`CreateWritableStream(startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm[, highWaterMark[, sizeAlgorithm ] ])@A は、次の手続きを遂行する: ◎ CreateWritableStream(startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm) performs the following steps:
- ~Assert: ~NOABRUPT `IsNonNegativeNumber$A( %highWaterMark ) ~EQ ~T ◎ Assert: ! IsNonNegativeNumber(highWaterMark) is true.
- %stream ~LET `新たな$ `WritableStream$I ◎ Let stream be a new WritableStream.
- ~NOABRUPT `InitializeWritableStream$A( %stream ) ◎ Perform ! InitializeWritableStream(stream).
- %controller ~LET `新たな$ `WritableStreamDefaultController$I ◎ Let controller be a new WritableStreamDefaultController.
- ~ABRUPT `SetUpWritableStreamDefaultController$A( ↓ ) ⇒# %stream, %controller, %startAlgorithm, %writeAlgorithm, %closeAlgorithm, %abortAlgorithm, %highWaterMark, %sizeAlgorithm ◎ Perform ? SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm).
- ~RET %stream ◎ Return stream.
注記: この抽象-演算は、 給された %startAlgorithm が投出するとき, そのときに限り, 例外を投出することになる。 ◎ This abstract operation will throw an exception if and only if the supplied startAlgorithm throws.
`InitializeWritableStream(stream)@A は、次の手続きを遂行する: ◎ InitializeWritableStream(stream) performs the following steps:
- %stream の ⇒# .`state$wS ~SET `writable^l, .`storedError$wS ~SET `undefined^jv, .`writer$wS ~SET `undefined^jv, .`controller$wS ~SET `undefined^jv, .`inFlightWriteRequest$wS ~SET `undefined^jv, .`closeRequest$wS ~SET `undefined^jv, .`inFlightCloseRequest$wS ~SET `undefined^jv, .`pendingAbortRequest$wS ~SET `undefined^jv, .`writeRequests$wS ~SET 新たな空`~list$, .`backpressure$wS ~SET ~F ◎ Set stream.[[state]] to "writable". ◎ Set stream.[[storedError]], stream.[[writer]], stream.[[controller]], stream.[[inFlightWriteRequest]], stream.[[closeRequest]], stream.[[inFlightCloseRequest]], and stream.[[pendingAbortRequest]] to undefined. ◎ Set stream.[[writeRequests]] to a new empty list. ◎ Set stream.[[backpressure]] to false.
`IsWritableStreamLocked(stream)@A は、次の手続きを遂行する: ◎ IsWritableStreamLocked(stream) performs the following steps:
- ~IF[ %stream.`writer$wS ~EQ `undefined^jv ] ⇒ ~RET ~F ◎ If stream.[[writer]] is undefined, return false.
- ~RET ~T ◎ Return true.
`SetUpWritableStreamDefaultWriter(writer, stream)@A は、次の手続きを遂行する: ◎ SetUpWritableStreamDefaultWriter(writer, stream) performs the following steps:
- ~IF[ ~NOABRUPT `IsWritableStreamLocked$A( %stream ) ~EQ ~T ] ⇒ ~THROW `TypeError$jE ◎ If ! IsWritableStreamLocked(stream) is true, throw a TypeError exception.
- %writer.`stream$wsW ~SET %stream ◎ Set writer.[[stream]] to stream.
- %stream.`writer$wS ~SET %writer ◎ Set stream.[[writer]] to writer.
- %state ~LET %stream.`state$wS ◎ Let state be stream.[[state]].
-
~IF[ %state ~EQ `writable^l ]: ◎ If state is "writable",
- ~IF[ ~NOABRUPT `WritableStreamCloseQueuedOrInFlight$A( %stream ) ~EQ ~F ]~AND[ %stream.`backpressure$wS ~EQ ~T ] ⇒ %writer.`readyPromise$wsW ~SET `新たな~promise$ ◎ If ! WritableStreamCloseQueuedOrInFlight(stream) is false and stream.[[backpressure]] is true, set writer.[[readyPromise]] to a new promise.
- ~ELSE ⇒ %writer.`readyPromise$wsW ~SET `解決される~promise$( `undefined^jv ) ◎ Otherwise, set writer.[[readyPromise]] to a promise resolved with undefined.
- %writer.`closedPromise$wsW ~SET `新たな~promise$ ◎ Set writer.[[closedPromise]] to a new promise.
-
~ELIF[ %state ~EQ `erroring^l ] ⇒ ◎ Otherwise, if state is "erroring",
- %writer.`readyPromise$wsW ~SET `却下される~promise$( %stream.`storedError$wS ) ◎ Set writer.[[readyPromise]] to a promise rejected with stream.[[storedError]].
- %writer.`readyPromise$wsW.`PromiseIsHandled^sl ~SET ~T ◎ Set writer.[[readyPromise]].[[PromiseIsHandled]] to true.
- %writer.`closedPromise$wsW ~SET `新たな~promise$ ◎ Set writer.[[closedPromise]] to a new promise.
-
~ELIF[ %state ~EQ `closed^l ] ⇒ ◎ Otherwise, if state is "closed",
- %writer.`readyPromise$wsW ~SET `解決される~promise$( `undefined^jv ) ◎ Set writer.[[readyPromise]] to a promise resolved with undefined.
- %writer.`closedPromise$wsW ~SET `解決される~promise$( `undefined^jv ) ◎ Set writer.[[closedPromise]] to a promise resolved with undefined.
-
~ELSE: ◎ Otherwise,
- ~Assert: %state ~EQ `errored^l ◎ Assert: state is "errored".
- %storedError ~LET %stream.`storedError$wS ◎ Let storedError be stream.[[storedError]].
- %writer.`readyPromise$wsW ~SET `却下される~promise$( %storedError ) ◎ Set writer.[[readyPromise]] to a promise rejected with storedError.
- %writer.`readyPromise$wsW.`PromiseIsHandled^sl ~SET ~T ◎ Set writer.[[readyPromise]].[[PromiseIsHandled]] to true.
- %writer.`closedPromise$wsW ~SET `却下される~promise$( %storedError ) ◎ Set writer.[[closedPromise]] to a promise rejected with storedError.
- %writer.`closedPromise$wsW.`PromiseIsHandled^sl ~SET ~T ◎ Set writer.[[closedPromise]].[[PromiseIsHandled]] to true.
`WritableStreamAbort(stream, reason)@A は、次の手続きを遂行する: ◎ WritableStreamAbort(stream, reason) performs the following steps:
- ~IF[ %stream.`state$wS ~IN { `closed^l, `errored^l } ] ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ If stream.[[state]] is "closed" or "errored", return a promise resolved with undefined.
- `中止-を通達する$aC( %stream.`controller$wS.`abortController$wsdC, %reason ) ◎ Signal abort on stream.[[controller]].[[abortController]] with reason.
- %state ~LET %stream.`state$wS ◎ Let state be stream.[[state]].
-
~IF[ %state ~IN { `closed^l, `errored^l } ] ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ If state is "closed" or "errored", return a promise resolved with undefined.
注記: ここでは、 %state を検査し直す — `中止-を通達する$aCときに走らせた作者~codeは、 %state を変更したかもしれないので。 ◎ We re-check the state because signaling abort runs author code and that might have changed the state.
- ~IF[ %stream.`pendingAbortRequest$wS ~NEQ `undefined^jv ] ⇒ ~RET %stream.`pendingAbortRequest$wS の`~promise$aR ◎ If stream.[[pendingAbortRequest]] is not undefined, return stream.[[pendingAbortRequest]]'s promise.
- ~Assert: %state ~IN { `writable^l, `erroring^l } ◎ Assert: state is "writable" or "erroring".
- %wasAlreadyErroring ~LET ~F ◎ Let wasAlreadyErroring be false.
-
~IF[ %state ~EQ `erroring^l ]: ◎ If state is "erroring",
- %wasAlreadyErroring ~SET ~T ◎ Set wasAlreadyErroring to true.
- %reason ~SET `undefined^jv ◎ Set reason to undefined.
- %promise ~LET `新たな~promise$ ◎ Let promise be a new promise.
- %stream.`pendingAbortRequest$wS ~SET 次を伴う,新たな`処理待ち中止-要請$ ⇒# `~promise$aR ~SET %promise, `事由$aR ~SET %reason, `すでに~errorしたか$aR ~SET %wasAlreadyErroring ◎ Set stream.[[pendingAbortRequest]] to a new pending abort request whose promise is promise, reason is reason, and was already erroring is wasAlreadyErroring.
- ~IF[ %wasAlreadyErroring ~EQ ~F ] ⇒ ~NOABRUPT `WritableStreamStartErroring$A( %stream, %reason ) ◎ If wasAlreadyErroring is false, perform ! WritableStreamStartErroring(stream, reason).
- ~RET %promise ◎ Return promise.
`WritableStreamClose(stream)@A は、次の手続きを遂行する: ◎ WritableStreamClose(stream) performs the following steps:
- %state ~LET %stream.`state$wS ◎ Let state be stream.[[state]].
- ~IF[ %state ~IN { `closed^l, `errored^l } ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ 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: ~NOABRUPT `WritableStreamCloseQueuedOrInFlight$A( %stream ) ~EQ ~F ◎ Assert: ! WritableStreamCloseQueuedOrInFlight(stream) is false.
- %promise ~LET `新たな~promise$ ◎ Let promise be a new promise.
- %stream.`closeRequest$wS ~SET %promise ◎ Set stream.[[closeRequest]] to promise.
- %writer ~LET %stream.`writer$wS ◎ Let writer be stream.[[writer]].
- ~IF[ %writer ~NEQ `undefined^jv ]~AND[ %stream.`backpressure$wS ~EQ ~T ]~AND[ %state ~EQ `writable^l ] ⇒ `~promiseを解決する$( %writer.`readyPromise$wsW, `undefined^jv ) ◎ If writer is not undefined, and stream.[[backpressure]] is true, and state is "writable", resolve writer.[[readyPromise]] with undefined.
- ~NOABRUPT `WritableStreamDefaultControllerClose$A( %stream.`controller$wS ) ◎ Perform ! WritableStreamDefaultControllerClose(stream.[[controller]]).
- ~RET %promise ◎ Return promise.
5.5.2. 制御器との~interface法
将来に,挙動が異なる可書~stream (既定の可読~streamと`可読~byte~stream$との間の区別に類似なそれ) も追加できるよう柔軟性を得るため、 `可書~stream$の内部~状態の多くの部分は, `WritableStreamDefaultController$I ~classにより~capsule化される。 ◎ 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.
各~制御器~classは、 2 つの内部~methodを定義する — それらは、 `WritableStream$I の各種~algoから~callされる: ◎ Each controller class defines two internal methods, which are called by the WritableStream algorithms:
- `AbortSteps@sl(%reason)
- ~streamが`中止-$されたときの反応として走らす,制御器の手続き。 制御器に格納されている状態を片付けて,`下層~sink$に伝えるために利用される。 ◎ The controller’s steps that run in reaction to the stream being aborted, used to clean up the state stored in the controller and inform the underlying sink.
- `ErrorSteps@sl()
- ~streamが~errorしたときの反応として走らす,制御器の手続き。 制御器に格納されている状態を片付けるために利用される。 ◎ The controller’s steps that run in reaction to the stream being errored, used to clean up the state stored in the controller.
(これらは、 制御器の型に応じて分岐することなく, 各種 `WritableStream$I ~algoから多形態的に~callできるよう、 抽象-演算としてではなく,内部~methodとして定義される。 まだ `WritableStreamDefaultController$I しか存在しないので、 今の所は理論上のものになっているが。) ◎ (These are defined as internal methods, instead of as abstract operations, so that they can be called polymorphically by the WritableStream algorithms, without having to branch on which type of controller is present. This is a bit theoretical for now, given that only WritableStreamDefaultController exists so far.)
この節の以降では、 上述とは別方向の抽象-演算について注力する: それらは、 制御器~実装により,[ 各自に結付けられた `WritableStream$I ~objに影響させる ]ために利用される。 これは、 制御器における内部~状態~変化を[ `WritableStream$I の公な~APIを通して開発者に可視になる結果 ]に翻訳する。 ◎ The rest of this section concerns abstract operations that go in the other direction: they are used by the controller implementation to affect its associated WritableStream object. This translates internal state changes of the controllerinto developer-facing results visible through the WritableStream's public API.
`WritableStreamAddWriteRequest(stream)@A は、次の手続きを遂行する: ◎ WritableStreamAddWriteRequest(stream) performs the following steps:
- ~Assert: ~NOABRUPT `IsWritableStreamLocked$A( %stream ) ~EQ ~T ◎ Assert: ! IsWritableStreamLocked(stream) is true.
- ~Assert: %stream.`state$wS ~EQ `writable^l ◎ Assert: stream.[[state]] is "writable".
- %promise ~LET `新たな~promise$ ◎ Let promise be a new promise.
- %stream.`writeRequests$wS に %promise を`付加する$ ◎ Append promise to stream.[[writeRequests]].
- ~RET %promise ◎ Return promise.
`WritableStreamCloseQueuedOrInFlight(stream)@A は、次の手続きを遂行する: ◎ WritableStreamCloseQueuedOrInFlight(stream) performs the following steps:
- ~IF[ %stream.`closeRequest$wS ~EQ `undefined^jv ]~AND[ %stream.`inFlightCloseRequest$wS ~EQ `undefined^jv ] ⇒ ~RET ~F ◎ If stream.[[closeRequest]] is undefined and stream.[[inFlightCloseRequest]] is undefined, return false.
- ~RET ~T ◎ Return true.
`WritableStreamDealWithRejection(stream, error)@A は、次の手続きを遂行する: ◎ WritableStreamDealWithRejection(stream, error) performs the following steps:
- %state ~LET %stream.`state$wS ◎ Let state be stream.[[state]].
-
~IF[ %state ~EQ `writable^l ]: ◎ If state is "writable",
- ~NOABRUPT `WritableStreamStartErroring$A( %stream, %error ) ◎ Perform ! WritableStreamStartErroring(stream, error).
- ~RET ◎ Return.
- ~Assert: %state ~EQ `erroring^l ◎ Assert: state is "erroring".
- ~NOABRUPT `WritableStreamFinishErroring$A( %stream ) ◎ Perform ! WritableStreamFinishErroring(stream).
`WritableStreamFinishErroring(stream)@A は、次の手続きを遂行する: ◎ WritableStreamFinishErroring(stream) performs the following steps:
- ~Assert: %stream.`state$wS ~EQ `erroring^l ◎ Assert: stream.[[state]] is "erroring".
- ~Assert: ~NOABRUPT `WritableStreamHasOperationMarkedInFlight$A( %stream ) ~EQ ~F ◎ Assert: ! WritableStreamHasOperationMarkedInFlight(stream) is false.
- %stream.`state$wS ~SET `errored^l ◎ Set stream.[[state]] to "errored".
- ~NOABRUPT %stream.`controller$wS.`ErrorSteps$sl() ◎ Perform ! stream.[[controller]].[[ErrorSteps]]().
- %storedError ~LET %stream.`storedError$wS ◎ Let storedError be stream.[[storedError]].
-
%stream.`writeRequests$wS を成す ~EACH( %writeRequest ) に対し: ◎ For each writeRequest of stream.[[writeRequests]]:
- `~promiseを却下する$( %writeRequest, %storedError ) ◎ Reject writeRequest with storedError.
- %stream.`writeRequests$wS ~SET 空`~list$ ◎ Set stream.[[writeRequests]] to an empty list.
-
~IF[ %stream.`pendingAbortRequest$wS ~EQ `undefined^jv ]: ◎ If stream.[[pendingAbortRequest]] is undefined,
- ~NOABRUPT `WritableStreamRejectCloseAndClosedPromiseIfNeeded$A( %stream) ◎ Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream).
- ~RET ◎ Return.
- %abortRequest ~LET %stream.`pendingAbortRequest$wS ◎ Let abortRequest be stream.[[pendingAbortRequest]].
- %stream.`pendingAbortRequest$wS ~SET `undefined^jv ◎ Set stream.[[pendingAbortRequest]] to undefined.
-
~IF[ %abortRequest の`すでに~errorしたか$aR ~EQ ~T ]: ◎ If abortRequest’s was already erroring is true,
- `~promiseを却下する$( %abortRequest の`~promise$aR, %storedError ) ◎ Reject abortRequest’s promise with storedError.
- ~NOABRUPT `WritableStreamRejectCloseAndClosedPromiseIfNeeded$A( %stream) ◎ Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream).
- ~RET ◎ Return.
-
%promise ~LET ~NOABRUPT %stream.`controller$wS.`AbortSteps$sl( %abortRequest の`事由$aR ) ◎ Let promise be ! stream.[[controller]].[[AbortSteps]](abortRequest’s reason).
-
%promise の`充足-時$には ◎ Upon fulfillment of promise,
- `~promiseを解決する$( %abortRequest の`~promise$aR, `undefined^jv ) ◎ Resolve abortRequest’s promise with undefined.
- ~NOABRUPT `WritableStreamRejectCloseAndClosedPromiseIfNeeded$A( %stream) ◎ Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream).
-
事由 %reason による %promise の`却下-時$には: ◎ Upon rejection of promise with reason reason,
- `~promiseを却下する$( %abortRequest の`~promise$aR, %reason ) ◎ Reject abortRequest’s promise with reason.
- ~NOABRUPT `WritableStreamRejectCloseAndClosedPromiseIfNeeded$A( %stream) ◎ Perform ! WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream).
-
`WritableStreamFinishInFlightClose(stream)@A は、次の手続きを遂行する: ◎ WritableStreamFinishInFlightClose(stream) performs the following steps:
- ~Assert: %stream.`inFlightCloseRequest$wS ~NEQ `undefined^jv ◎ Assert: stream.[[inFlightCloseRequest]] is not undefined.
- `~promiseを解決する$( %stream.`inFlightCloseRequest$wS, `undefined^jv ) ◎ Resolve stream.[[inFlightCloseRequest]] with undefined.
- %stream.`inFlightCloseRequest$wS ~SET `undefined^jv ◎ Set stream.[[inFlightCloseRequest]] to undefined.
- %state ~LET %stream.`state$wS ◎ Let state be stream.[[state]].
- ~Assert: %stream.`state$wS ~IN { `writable^l, `erroring^l } ◎ Assert: stream.[[state]] is "writable" or "erroring".
-
~IF[ %state ~EQ `erroring^l ]: ◎ If state is "erroring",
- %stream.`storedError$wS ~SET `undefined^jv ◎ Set stream.[[storedError]] to undefined.
-
~IF[ %stream.`pendingAbortRequest$wS ~NEQ `undefined^jv ]: ◎ If stream.[[pendingAbortRequest]] is not undefined,
- `~promiseを解決する$( %stream.`pendingAbortRequest$wS の`~promise$aR, `undefined^jv ) ◎ Resolve stream.[[pendingAbortRequest]]'s promise with undefined.
- %stream.`pendingAbortRequest$wS ~SET `undefined^jv ◎ Set stream.[[pendingAbortRequest]] to undefined.
- %stream.`state$wS ~SET `closed^l ◎ Set stream.[[state]] to "closed".
- %writer ~LET %stream.`writer$wS ◎ Let writer be stream.[[writer]].
- ~IF[ %writer ~NEQ `undefined^jv ] ⇒ `~promiseを解決する$( %writer.`closedPromise$wsW, `undefined^jv ) ◎ If writer is not undefined, resolve writer.[[closedPromise]] with undefined.
- ~Assert: %stream.`pendingAbortRequest$wS ~EQ `undefined^jv ◎ Assert: stream.[[pendingAbortRequest]] is undefined.
- ~Assert: %stream.`storedError$wS ~EQ `undefined^jv ◎ Assert: stream.[[storedError]] is undefined.
`WritableStreamFinishInFlightCloseWithError(stream, error)@A は、次の手続きを遂行する: ◎ WritableStreamFinishInFlightCloseWithError(stream, error) performs the following steps:
- ~Assert: %stream.`inFlightCloseRequest$wS ~NEQ `undefined^jv ◎ Assert: stream.[[inFlightCloseRequest]] is not undefined.
- `~promiseを却下する$( %stream.`inFlightCloseRequest$wS, %error ) ◎ Reject stream.[[inFlightCloseRequest]] with error.
- %stream.`inFlightCloseRequest$wS ~SET `undefined^jv ◎ Set stream.[[inFlightCloseRequest]] to undefined.
- ~Assert: %stream.`state$wS ~IN { `writable^l, `erroring^l } ◎ Assert: stream.[[state]] is "writable" or "erroring".
-
~IF[ %stream.`pendingAbortRequest$wS ~NEQ `undefined^jv ]: ◎ If stream.[[pendingAbortRequest]] is not undefined,
- `~promiseを却下する$( %stream.`pendingAbortRequest$wS の`~promise$aR, %error ) ◎ Reject stream.[[pendingAbortRequest]]'s promise with error.
- %stream.`pendingAbortRequest$wS ~SET `undefined^jv ◎ Set stream.[[pendingAbortRequest]] to undefined.
- ~NOABRUPT `WritableStreamDealWithRejection$A( %stream, %error ) ◎ Perform ! WritableStreamDealWithRejection(stream, error).
`WritableStreamFinishInFlightWrite(stream)@A は、次の手続きを遂行する: ◎ WritableStreamFinishInFlightWrite(stream) performs the following steps:
- ~Assert: %stream.`inFlightWriteRequest$wS ~NEQ `undefined^jv ◎ Assert: stream.[[inFlightWriteRequest]] is not undefined.
- `~promiseを解決する$( %stream.`inFlightWriteRequest$wS, `undefined^jv ) ◎ Resolve stream.[[inFlightWriteRequest]] with undefined.
- %stream.`inFlightWriteRequest$wS ~SET `undefined^jv ◎ Set stream.[[inFlightWriteRequest]] to undefined.
`WritableStreamFinishInFlightWriteWithError(stream, error)@A は、次の手続きを遂行する: ◎ WritableStreamFinishInFlightWriteWithError(stream, error) performs the following steps:
- ~Assert: %stream.`inFlightWriteRequest$wS ~NEQ `undefined^jv ◎ Assert: stream.[[inFlightWriteRequest]] is not undefined.
- `~promiseを却下する$( %stream.`inFlightWriteRequest$wS, %error ) ◎ Reject stream.[[inFlightWriteRequest]] with error.
- %stream.`inFlightWriteRequest$wS ~SET `undefined^jv ◎ Set stream.[[inFlightWriteRequest]] to undefined.
- ~Assert: %stream.`state$wS ~IN { `writable^l, `erroring^l } ◎ Assert: stream.[[state]] is "writable" or "erroring".
- ~NOABRUPT `WritableStreamDealWithRejection$A( %stream, %error ) ◎ Perform ! WritableStreamDealWithRejection(stream, error).
`WritableStreamHasOperationMarkedInFlight(stream)@A は、次の手続きを遂行する: ◎ WritableStreamHasOperationMarkedInFlight(stream) performs the following steps:
- ~IF[ %stream.`inFlightWriteRequest$wS ~EQ `undefined^jv ]~AND[ %stream.`inFlightCloseRequest$wS ~EQ `undefined^jv ] ⇒ ~RET ~F ◎ If stream.[[inFlightWriteRequest]] is undefined and stream.[[inFlightCloseRequest]] is undefined, return false.
- ~RET ~T ◎ Return true.
`WritableStreamMarkCloseRequestInFlight(stream)@A は、次の手続きを遂行する: ◎ WritableStreamMarkCloseRequestInFlight(stream) performs the following steps:
- ~Assert: %stream.`inFlightCloseRequest$wS ~EQ `undefined^jv ◎ Assert: stream.[[inFlightCloseRequest]] is undefined.
- ~Assert: %stream.`closeRequest$wS ~NEQ `undefined^jv ◎ Assert: stream.[[closeRequest]] is not undefined.
- %stream.`inFlightCloseRequest$wS ~SET %stream.`closeRequest$wS ◎ Set stream.[[inFlightCloseRequest]] to stream.[[closeRequest]].
- %stream.`closeRequest$wS ~SET `undefined^jv ◎ Set stream.[[closeRequest]] to undefined.
`WritableStreamMarkFirstWriteRequestInFlight(stream)@A は、次の手続きを遂行する: ◎ WritableStreamMarkFirstWriteRequestInFlight(stream) performs the following steps:
- ~Assert: %stream.`inFlightWriteRequest$wS ~EQ `undefined^jv ◎ Assert: stream.[[inFlightWriteRequest]] is undefined.
- ~Assert: %stream.`writeRequests$wS は`空$でない ◎ Assert: stream.[[writeRequests]] is not empty.
- %writeRequest ~LET %stream.`writeRequests$wS[0] ◎ Let writeRequest be stream.[[writeRequests]][0].
- %stream.`writeRequests$wS から %writeRequest を`除去する$ ◎ Remove writeRequest from stream.[[writeRequests]].
- %stream.`inFlightWriteRequest$wS ~SET %writeRequest ◎ Set stream.[[inFlightWriteRequest]] to writeRequest.
`WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream)@A は、次の手続きを遂行する: ◎ WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream) performs the following steps:
- ~Assert: %stream.`state$wS ~EQ `errored^l ◎ Assert: stream.[[state]] is "errored".
-
~IF[ %stream.`closeRequest$wS ~NEQ `undefined^jv ]: ◎ If stream.[[closeRequest]] is not undefined,
- ~Assert: %stream.`inFlightCloseRequest$wS ~EQ `undefined^jv ◎ Assert: stream.[[inFlightCloseRequest]] is undefined.
- `~promiseを却下する$( %stream.`closeRequest$wS, %stream.`storedError$wS ) ◎ Reject stream.[[closeRequest]] with stream.[[storedError]].
- %stream.`closeRequest$wS ~SET `undefined^jv ◎ Set stream.[[closeRequest]] to undefined.
- %writer ~LET %stream.`writer$wS ◎ Let writer be stream.[[writer]].
-
~IF[ %writer ~NEQ `undefined^jv ]: ◎ If writer is not undefined,
- `~promiseを却下する$( %writer.`closedPromise$wsW, %stream.`storedError$wS ) ◎ Reject writer.[[closedPromise]] with stream.[[storedError]].
- %writer.`closedPromise$wsW.`PromiseIsHandled^sl ~SET ~T ◎ Set writer.[[closedPromise]].[[PromiseIsHandled]] to true.
`WritableStreamStartErroring(stream, reason)@A は、次の手続きを遂行する: ◎ WritableStreamStartErroring(stream, reason) performs the following steps:
- ~Assert: %stream.`storedError$wS ~EQ `undefined^jv ◎ Assert: stream.[[storedError]] is undefined.
- ~Assert: %stream.`state$wS ~EQ `writable^l ◎ Assert: stream.[[state]] is "writable".
- %controller ~LET %stream.`controller$wS ◎ Let controller be stream.[[controller]].
- ~Assert: %controller ~NEQ `undefined^jv ◎ Assert: controller is not undefined.
- %stream.`state$wS ~SET `erroring^l ◎ Set stream.[[state]] to "erroring".
- %stream.`storedError$wS ~SET %reason ◎ Set stream.[[storedError]] to reason.
- %writer ~LET %stream.`writer$wS ◎ Let writer be stream.[[writer]].
- ~IF[ %writer ~NEQ `undefined^jv ] ⇒ ~NOABRUPT `WritableStreamDefaultWriterEnsureReadyPromiseRejected$A( %writer, %reason ) ◎ If writer is not undefined, perform ! WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason).
- ~IF[ ~NOABRUPT `WritableStreamHasOperationMarkedInFlight$A( %stream ) ~EQ ~F ]~AND[ %controller.`started$wsdC ~EQ ~T ] ⇒ ~NOABRUPT `WritableStreamFinishErroring$A( %stream ) ◎ If ! WritableStreamHasOperationMarkedInFlight(stream) is false and controller.[[started]] is true, perform ! WritableStreamFinishErroring(stream).
`WritableStreamUpdateBackpressure(stream, backpressure)@A は、次の手続きを遂行する: ◎ WritableStreamUpdateBackpressure(stream, backpressure) performs the following steps:
- ~Assert: %stream.`state$wS ~EQ `writable^l ◎ Assert: stream.[[state]] is "writable".
- ~Assert: ~NOABRUPT `WritableStreamCloseQueuedOrInFlight$A( %stream ) ~EQ ~F ◎ Assert: ! WritableStreamCloseQueuedOrInFlight(stream) is false.
- %writer ~LET %stream.`writer$wS ◎ Let writer be stream.[[writer]].
-
~IF[ %writer ~NEQ `undefined^jv ]~AND[ %backpressure ~NEQ %stream.`backpressure$wS ]: ◎ If writer is not undefined and backpressure is not stream.[[backpressure]],
- ~IF[ %backpressure ~EQ ~T ] ⇒ %writer.`readyPromise$wsW ~SET `新たな~promise$ ◎ If backpressure is true, set writer.[[readyPromise]] to a new promise.
-
~ELSE: ◎ Otherwise,
- ~Assert: %backpressure ~EQ ~F ◎ Assert: backpressure is false.
- `~promiseを解決する$( %writer.`readyPromise$wsW, `undefined^jv ) ◎ Resolve writer.[[readyPromise]] with undefined.
- %stream.`backpressure$wS ~SET %backpressure ◎ Set stream.[[backpressure]] to backpressure.
5.5.3. 書込器
以下に与える抽象-演算は、 `WritableStreamDefaultWriter$I ~instanceの実装と操作を~supportする。 ◎ The following abstract operations support the implementation and manipulation of WritableStreamDefaultWriter instances.
`WritableStreamDefaultWriterAbort(writer, reason)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultWriterAbort(writer, reason) performs the following steps:
- %stream ~LET %writer.`stream$wsW ◎ Let stream be writer.[[stream]].
- ~Assert: %stream ~NEQ `undefined^jv ◎ Assert: stream is not undefined.
- ~RET ~NOABRUPT `WritableStreamAbort$A( %stream, %reason ) ◎ Return ! WritableStreamAbort(stream, reason).
`WritableStreamDefaultWriterClose(writer)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultWriterClose(writer) performs the following steps:
- %stream ~LET %writer.`stream$wsW ◎ Let stream be writer.[[stream]].
- ~Assert: %stream ~NEQ `undefined^jv ◎ Assert: stream is not undefined.
- ~RET ~NOABRUPT `WritableStreamClose$A( %stream ) ◎ Return ! WritableStreamClose(stream).
`WritableStreamDefaultWriterCloseWithErrorPropagation(writer)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultWriterCloseWithErrorPropagation(writer) performs the following steps:
- %stream ~LET %writer.`stream$wsW ◎ Let stream be writer.[[stream]].
- ~Assert: %stream ~NEQ `undefined^jv ◎ Assert: stream is not undefined.
- %state ~LET %stream.`state$wS ◎ Let state be stream.[[state]].
- ~IF[ ~NOABRUPT `WritableStreamCloseQueuedOrInFlight$A( %stream ) ~EQ ~T ]~OR[ %state ~EQ `closed^l ] ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ If ! WritableStreamCloseQueuedOrInFlight(stream) is true or state is "closed", return a promise resolved with undefined.
- ~IF[ %state ~EQ `errored^l ] ⇒ ~RET `却下される~promise$( %stream.`storedError$wS ) ◎ 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 ~NOABRUPT `WritableStreamDefaultWriterClose$A( %writer ) ◎ Return ! WritableStreamDefaultWriterClose(writer).
注記: この抽象-演算は、[ `ReadableStream$I の `pipeTo()$rs における~error伝播の意味論 ]を実装し易くするためにある。 ◎ This abstract operation helps implement the error propagation semantics of ReadableStream's pipeTo().
`WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, error)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, error) performs the following steps:
- ~IF[ %writer.`closedPromise$wsW.`PromiseState^sl ~EQ `pending^l ] ⇒ `~promiseを却下する$( %writer.`closedPromise$wsW, %error ) ◎ If writer.[[closedPromise]].[[PromiseState]] is "pending", reject writer.[[closedPromise]] with error.
- ~ELSE ⇒ %writer.`closedPromise$wsW ~SET `却下される~promise$( %error ) ◎ Otherwise, set writer.[[closedPromise]] to a promise rejected with error.
- %writer.`closedPromise$wsW.`PromiseIsHandled^sl ~SET ~T ◎ Set writer.[[closedPromise]].[[PromiseIsHandled]] to true.
`WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, error)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, error) performs the following steps:
- ~IF[ %writer.`readyPromise$wsW.`PromiseState^sl ~EQ `pending^l ] ⇒ `~promiseを却下する$( %writer.`readyPromise$wsW, %error ) ◎ If writer.[[readyPromise]].[[PromiseState]] is "pending", reject writer.[[readyPromise]] with error.
- ~ELSE ⇒ %writer.`readyPromise$wsW ~SET `却下される~promise$( %error ) ◎ Otherwise, set writer.[[readyPromise]] to a promise rejected with error.
- %writer.`readyPromise$wsW.`PromiseIsHandled^sl ~SET ~T ◎ Set writer.[[readyPromise]].[[PromiseIsHandled]] to true.
`WritableStreamDefaultWriterGetDesiredSize(writer)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultWriterGetDesiredSize(writer) performs the following steps:
- %stream ~LET %writer.`stream$wsW ◎ Let stream be writer.[[stream]].
- %state ~LET %stream.`state$wS ◎ Let state be stream.[[state]].
- ~IF[ %state ~IN { `errored^l, `erroring^l } ] ⇒ ~RET ~NULL ◎ If state is "errored" or "erroring", return null.
- ~IF[ %state ~EQ `closed^l ] ⇒ ~RET 0 ◎ If state is "closed", return 0.
- ~RET ~NOABRUPT `WritableStreamDefaultControllerGetDesiredSize$A( %stream.`controller$wS ) ◎ Return ! WritableStreamDefaultControllerGetDesiredSize(stream.[[controller]]).
`WritableStreamDefaultWriterRelease(writer)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultWriterRelease(writer) performs the following steps:
- %stream ~LET %writer.`stream$wsW ◎ Let stream be writer.[[stream]].
- ~Assert: %stream ~NEQ `undefined^jv ◎ Assert: stream is not undefined.
- ~Assert: %stream.`writer$wS ~EQ %writer ◎ Assert: stream.[[writer]] is writer.
- %releasedError ~LET 新たな `TypeError$jE ◎ Let releasedError be a new TypeError.
- ~NOABRUPT `WritableStreamDefaultWriterEnsureReadyPromiseRejected$A( %writer, %releasedError) ◎ Perform ! WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError).
- ~NOABRUPT `WritableStreamDefaultWriterEnsureClosedPromiseRejected$A( %writer, %releasedError) ◎ Perform ! WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedError).
- %stream.`writer$wS ~SET `undefined^jv ◎ Set stream.[[writer]] to undefined.
- %writer.`stream$wsW ~SET `undefined^jv ◎ Set writer.[[stream]] to undefined.
`WritableStreamDefaultWriterWrite(writer, chunk)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultWriterWrite(writer, chunk) performs the following steps:
- %stream ~LET %writer.`stream$wsW ◎ Let stream be writer.[[stream]].
- ~Assert: %stream ~NEQ `undefined^jv ◎ Assert: stream is not undefined.
- %controller ~LET %stream.`controller$wS ◎ Let controller be stream.[[controller]].
- %chunkSize ~LET ~NOABRUPT `WritableStreamDefaultControllerGetChunkSize$A(%controller, %chunk) ◎ Let chunkSize be ! WritableStreamDefaultControllerGetChunkSize(controller, chunk).
- ~IF[ %stream ~NEQ %writer.`stream$wsW ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) ◎ If stream is not equal to writer.[[stream]], return a promise rejected with a TypeError exception.
- %state ~LET %stream.`state$wS ◎ Let state be stream.[[state]].
- ~IF[ %state ~EQ `errored^l ] ⇒ ~RET `却下される~promise$( %stream.`storedError$wS ) ◎ If state is "errored", return a promise rejected with stream.[[storedError]].
- ~IF[ ~NOABRUPT `WritableStreamCloseQueuedOrInFlight$A( %stream ) ~EQ ~T ]~OR[ %state ~NEQ `closed^l ] ⇒ ~RET `却下される~promise$( `TypeError$jE 例外 ) — これは、 ~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 `却下される~promise$( %stream.`storedError$wS ) ◎ If state is "erroring", return a promise rejected with stream.[[storedError]].
- ~Assert: %state ~EQ `writable^l ◎ Assert: state is "writable".
- %promise ~LET ~NOABRUPT `WritableStreamAddWriteRequest$A( %stream ) ◎ Let promise be ! WritableStreamAddWriteRequest(stream).
- ~NOABRUPT `WritableStreamDefaultControllerWrite$A( %controller, %chunk, %chunkSize ) ◎ Perform ! WritableStreamDefaultControllerWrite(controller, chunk, chunkSize).
- ~RET %promise ◎ Return promise.
5.5.4. 既定の制御器
以下に与える抽象-演算は、 `WritableStreamDefaultController$I ~classの実装を~supportする。 ◎ The following abstract operations support the implementation of the WritableStreamDefaultController class.
`SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm)@A は、次の手続きを遂行する: ◎ SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm) performs the following steps:
- ~Assert: %stream は `WritableStream$I を`実装する$ ◎ Assert: stream implements WritableStream.
- ~Assert: %stream.`controller$wS ~EQ `undefined^jv ◎ Assert: stream.[[controller]] is undefined.
- %controller.`stream$wsdC ~SET %stream ◎ Set controller.[[stream]] to stream.
- %stream.`controller$wS ~SET %controller ◎ Set stream.[[controller]] to controller.
- ~NOABRUPT `ResetQueue$A( %controller ) ◎ Perform ! ResetQueue(controller).
- %controller.`abortController$wsdC ~SET 新たな `AbortController$I — その ⇒# .`started$wsdC ~SET ~F, .`strategySizeAlgorithm$wsdC ~SET %sizeAlgorithm, .`strategyHWM$wsdC ~SET %highWaterMark, .`writeAlgorithm$wsdC ~SET %writeAlgorithm, .`closeAlgorithm$wsdC ~SET %closeAlgorithm, .`abortAlgorithm$wsdC ~SET %abortAlgorithm ◎ Set controller.[[abortController]] to a new AbortController. ◎ 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 ~NOABRUPT `WritableStreamDefaultControllerGetBackpressure$A( %controller ) ◎ Let backpressure be ! WritableStreamDefaultControllerGetBackpressure(controller).
- ~NOABRUPT `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 `解決される~promise$( %startResult ) ◎ Let startPromise be a promise resolved with startResult.
-
%startPromise の`充足-時$には: ◎ Upon fulfillment of startPromise,
- ~Assert: %stream.`state$wS ~IN { `writable^l, `erroring^l } ◎ Assert: stream.[[state]] is "writable" or "erroring".
- %controller.`started$wsdC ~SET ~T ◎ Set controller.[[started]] to true.
- ~NOABRUPT `WritableStreamDefaultControllerAdvanceQueueIfNeeded$A( %controller ) ◎ Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).
-
事由 %r による %startPromise の`却下-時$には: ◎ Upon rejection of startPromise with reason r,
- ~Assert: %stream.`state$wS ~IN { `writable^l, `erroring^l } ◎ Assert: stream.[[state]] is "writable" or "erroring".
- %controller.`started$wsdC ~SET ~T ◎ Set controller.[[started]] to true.
- ~NOABRUPT `WritableStreamDealWithRejection$A( %stream, %r ) ◎ Perform ! WritableStreamDealWithRejection(stream, r).
-
`SetUpWritableStreamDefaultControllerFromUnderlyingSink(stream, underlyingSink, underlyingSinkDict, highWaterMark, sizeAlgorithm)@A は、次の手続きを遂行する: ◎ SetUpWritableStreamDefaultControllerFromUnderlyingSink(stream, underlyingSink, underlyingSinkDict, highWaterMark, sizeAlgorithm) performs the following steps:
- %controller ~LET `新たな$ `WritableStreamDefaultController$I ◎ Let controller be a new WritableStreamDefaultController.
- %startAlgorithm ~LET 次を走らす~algo ⇒ ~RET `undefined^jv ◎ Let startAlgorithm be an algorithm that returns undefined.
- %writeAlgorithm ~LET 次を走らす~algo ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ Let writeAlgorithm be an algorithm that returns a promise resolved with undefined.
- %closeAlgorithm ~LET 次を走らす~algo ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ Let closeAlgorithm be an algorithm that returns a promise resolved with undefined.
- %abortAlgorithm ~LET 次を走らす~algo ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ Let abortAlgorithm be an algorithm that returns a promise resolved with undefined.
- ~IF[ %underlyingSinkDict[ "`start$usk" ] ~NEQ ε ] ⇒ %startAlgorithm ~SET 次を走らす~algo ⇒ ~RET `~callback関数を呼出す$( %underlyingSinkDict[ "`start$usk" ], « %controller », `投出し直す^i, %underlyingSink ) ◎ If underlyingSinkDict["start"] exists, then set startAlgorithm to an algorithm which returns the result of invoking underlyingSinkDict["start"] with argument list « controller », exception behavior "rethrow", and callback this value underlyingSink.
- ~IF[ %underlyingSinkDict[ "`write$usk" ] ~NEQ ε ] ⇒ %writeAlgorithm ~SET 所与の ( %chunk ) に対し,次を走らす~algo ⇒ ~RET `~callback関数を呼出す$( %underlyingSinkDict[ "`write$usk" ], « %chunk, %controller », ε, %underlyingSink ) ◎ If underlyingSinkDict["write"] exists, then set writeAlgorithm to an algorithm which takes an argument chunk and returns the result of invoking underlyingSinkDict["write"] with argument list « chunk, controller » and callback this value underlyingSink.
- ~IF[ %underlyingSinkDict[ "`close$usk" ] ~NEQ ε ] ⇒ %closeAlgorithm ~SET 次を走らす~algo ⇒ ~RET `~callback関数を呼出す$( %underlyingSinkDict[ "`close$usk" ], «», ε, %underlyingSink ) ◎ If underlyingSinkDict["close"] exists, then set closeAlgorithm to an algorithm which returns the result of invoking underlyingSinkDict["close"] with argument list «» and callback this value underlyingSink.
- ~IF[ %underlyingSinkDict[ "`abort$usk" ] ~NEQ ε ] ⇒ %abortAlgorithm ~SET 所与の ( %reason ) に対し,次を走らす~algo ⇒ ~RET `~callback関数を呼出す$( %underlyingSinkDict[ "`abort$usk" ], « %reason », ε, %underlyingSink ) ◎ If underlyingSinkDict["abort"] exists, then set abortAlgorithm to an algorithm which takes an argument reason and returns the result of invoking underlyingSinkDict["abort"] with argument list « reason » and callback this value underlyingSink.
- ~ABRUPT `SetUpWritableStreamDefaultController$A( ↓ ) ⇒# %stream, %controller, %startAlgorithm, %writeAlgorithm, %closeAlgorithm, %abortAlgorithm, %highWaterMark, %sizeAlgorithm ◎ Perform ? SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm).
`WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller) performs the following steps:
- %stream ~LET %controller.`stream$wsdC ◎ Let stream be controller.[[stream]].
- ~IF[ %controller.`started$wsdC ~EQ ~F ] ⇒ ~RET ◎ If controller.[[started]] is false, return.
- ~IF[ %stream.`inFlightWriteRequest$wS ~NEQ `undefined^jv ] ⇒ ~RET ◎ If stream.[[inFlightWriteRequest]] is not undefined, return.
- %state ~LET %stream.`state$wS ◎ Let state be stream.[[state]].
- ~Assert: %state ~NIN { `closed^l, `errored^l } ◎ Assert: state is not "closed" or "errored".
-
~IF[ %state ~EQ `erroring^l ]: ◎ If state is "erroring",
- ~NOABRUPT `WritableStreamFinishErroring$A( %stream ) ◎ Perform ! WritableStreamFinishErroring(stream).
- ~RET ◎ Return.
- ~IF[ %controller.`queue$wsdC は空である ] ⇒ ~RET ◎ If controller.[[queue]] is empty, return.
- %value ~LET ~NOABRUPT `PeekQueueValue$A( %controller ) ◎ Let value be ! PeekQueueValue(controller).
- ~IF[ %value ~EQ `~close~sentinel$i ] ⇒ ~NOABRUPT `WritableStreamDefaultControllerProcessClose$A( %controller ) ◎ If value is the close sentinel, perform ! WritableStreamDefaultControllerProcessClose(controller).
- ~ELSE ⇒ ~NOABRUPT `WritableStreamDefaultControllerProcessWrite$A( %controller, %value ) ◎ Otherwise, perform ! WritableStreamDefaultControllerProcessWrite(controller, value).
`WritableStreamDefaultControllerClearAlgorithms(controller)@A は、[ ~streamが~closeされるか~errorして, 各種~algoが それ以上~実行されなくなったとき ]に~callされる。 これは、 各種~algoへの参照を除去することにより, `下層~sink$( `WritableStream$I ~obj)自身が — まだ参照されていても — ~garbage収集されることを許可する。 ◎ WritableStreamDefaultControllerClearAlgorithms(controller) 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.
注記: これは、 `弱い参照@https://github.com/tc39/proposal-weakrefs/$を利用すると観測-可能になる。 詳細は `tc39/proposal-weakrefs#31@https://github.com/tc39/proposal-weakrefs/issues/31$ を見よ。 ◎ This is observable using weak references. See tc39/proposal-weakrefs#31 for more detail.
それは、次の手続きを遂行する: ◎ It performs the following steps:
- %controller の ⇒# .`writeAlgorithm$wsdC ~SET `undefined^jv, .`closeAlgorithm$wsdC ~SET `undefined^jv, .`abortAlgorithm$wsdC ~SET `undefined^jv, .`strategySizeAlgorithm$wsdC ~SET `undefined^jv ◎ Set controller.[[writeAlgorithm]] to undefined. ◎ Set controller.[[closeAlgorithm]] to undefined. ◎ Set controller.[[abortAlgorithm]] to undefined. ◎ Set controller.[[strategySizeAlgorithm]] to undefined.
注記: この~algoは、[ 一部の~~際どい事例では複数回 遂行される ]ことになるが, 2 回目~以降は何もしない。 ◎ This algorithm will be performed multiple times in some edge cases. After the first time it will do nothing.
`WritableStreamDefaultControllerClose(controller)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultControllerClose(controller) performs the following steps:
- ~NOABRUPT `EnqueueValueWithSize$A( %controller, `~close~sentinel$i, 0 ) ◎ Perform ! EnqueueValueWithSize(controller, close sentinel, 0).
- ~NOABRUPT `WritableStreamDefaultControllerAdvanceQueueIfNeeded$A( %controller ) ◎ Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).
`WritableStreamDefaultControllerError(controller, error)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultControllerError(controller, error) performs the following steps:
- %stream ~LET %controller.`stream$wsdC ◎ Let stream be controller.[[stream]].
- ~Assert: %stream.`state$wS ~EQ `writable^l ◎ Assert: stream.[[state]] is "writable".
- ~NOABRUPT `WritableStreamDefaultControllerClearAlgorithms$A( %controller ) ◎ Perform ! WritableStreamDefaultControllerClearAlgorithms(controller).
- ~NOABRUPT `WritableStreamStartErroring$A( %stream, %error ) ◎ Perform ! WritableStreamStartErroring(stream, error).
`WritableStreamDefaultControllerErrorIfNeeded(controller, error)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultControllerErrorIfNeeded(controller, error) performs the following steps:
- ~IF[ %controller.`stream$wsdC.`state$wS ~EQ `writable^l ] ⇒ ~NOABRUPT `WritableStreamDefaultControllerError$A( %controller, %error ) ◎ If controller.[[stream]].[[state]] is "writable", perform ! WritableStreamDefaultControllerError(controller, error).
`WritableStreamDefaultControllerGetBackpressure(controller)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultControllerGetBackpressure(controller) performs the following steps:
- %desiredSize ~LET ~NOABRUPT `WritableStreamDefaultControllerGetDesiredSize$A( %controller ) ◎ Let desiredSize be ! WritableStreamDefaultControllerGetDesiredSize(controller).
- ~RET ~IS[ %desiredSize ~LTE 0 ] ◎ Return true if desiredSize ≤ 0, or false otherwise.
`WritableStreamDefaultControllerGetChunkSize(controller, chunk)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultControllerGetChunkSize(controller, chunk) performs the following steps:
- %returnValue ~LET 次を遂行した結果を`完了~record$として解釈した結果 ⇒ %controller.`strategySizeAlgorithm$wsdC( %chunk ) ◎ Let returnValue be the result of performing controller.[[strategySizeAlgorithm]], passing in chunk, and interpreting the result as a completion record.
-
~IF[ %returnValue は`中途完了^である ]: ◎ If returnValue is an abrupt completion,
- ~NOABRUPT `WritableStreamDefaultControllerErrorIfNeeded$A( %controller, %returnValue.`Value^sl ) ◎ Perform ! WritableStreamDefaultControllerErrorIfNeeded(controller, returnValue.[[Value]]).
- ~RET 1 ◎ Return 1.
- ~RET %returnValue.`Value^sl ◎ Return returnValue.[[Value]].
`WritableStreamDefaultControllerGetDesiredSize(controller)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultControllerGetDesiredSize(controller) performs the following steps:
- ~RET %controller.`strategyHWM$wsdC ~MINUS %controller.`queueTotalSize$wsdC ◎ Return controller.[[strategyHWM]] − controller.[[queueTotalSize]].
`WritableStreamDefaultControllerProcessClose(controller)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultControllerProcessClose(controller) performs the following steps:
- %stream ~LET %controller.`stream$wsdC ◎ Let stream be controller.[[stream]].
- ~NOABRUPT `WritableStreamMarkCloseRequestInFlight$A( %stream ) ◎ Perform ! WritableStreamMarkCloseRequestInFlight(stream).
- ~NOABRUPT `DequeueValue$A( %controller ) ◎ Perform ! DequeueValue(controller).
- ~Assert: %controller.`queue$wsdC は空である ◎ Assert: controller.[[queue]] is empty.
- %sinkClosePromise ~LET %controller.`closeAlgorithm$wsdC() ◎ Let sinkClosePromise be the result of performing controller.[[closeAlgorithm]].
- ~NOABRUPT `WritableStreamDefaultControllerClearAlgorithms$A( %controller ) ◎ Perform ! WritableStreamDefaultControllerClearAlgorithms(controller).
-
-
%sinkClosePromise の`充足-時$には: ◎ Upon fulfillment of sinkClosePromise,
- ~NOABRUPT `WritableStreamFinishInFlightClose$A( %stream ) ◎ Perform ! WritableStreamFinishInFlightClose(stream).
-
事由 %reason による %sinkClosePromise の`却下-時$には: ◎ Upon rejection of sinkClosePromise with reason reason,
- ~NOABRUPT `WritableStreamFinishInFlightCloseWithError$A( %stream, %reason ) ◎ Perform ! WritableStreamFinishInFlightCloseWithError(stream, reason).
-
`WritableStreamDefaultControllerProcessWrite(controller, chunk)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultControllerProcessWrite(controller, chunk) performs the following steps:
- %stream ~LET %controller.`stream$wsdC ◎ Let stream be controller.[[stream]].
- ~NOABRUPT `WritableStreamMarkFirstWriteRequestInFlight$A( %stream ) ◎ Perform ! WritableStreamMarkFirstWriteRequestInFlight(stream).
-
%sinkWritePromise ~LET %controller.`writeAlgorithm$wsdC( %chunk ) ◎ Let sinkWritePromise be the result of performing controller.[[writeAlgorithm]], passing in chunk.
-
%sinkWritePromise の`充足-時$には: ◎ Upon fulfillment of sinkWritePromise,
- ~NOABRUPT `WritableStreamFinishInFlightWrite$A( %stream ) ◎ Perform ! WritableStreamFinishInFlightWrite(stream).
- %state ~LET %stream.`state$wS ◎ Let state be stream.[[state]].
- ~Assert: %state ~IN { `writable^l, `erroring^l } ◎ Assert: state is "writable" or "erroring".
- ~NOABRUPT `DequeueValue$A( %controller ) ◎ Perform ! DequeueValue(controller).
-
~IF[ ~NOABRUPT `WritableStreamCloseQueuedOrInFlight$A( %stream ) ~EQ ~F ]~AND[ %state ~EQ `writable^l ]: ◎ If ! WritableStreamCloseQueuedOrInFlight(stream) is false and state is "writable",
- %backpressure ~LET ~NOABRUPT `WritableStreamDefaultControllerGetBackpressure$A( %controller ) ◎ Let backpressure be ! WritableStreamDefaultControllerGetBackpressure(controller).
- ~NOABRUPT `WritableStreamUpdateBackpressure$A( %stream, %backpressure ) ◎ Perform ! WritableStreamUpdateBackpressure(stream, backpressure).
- ~NOABRUPT `WritableStreamDefaultControllerAdvanceQueueIfNeeded$A( %controller ) ◎ Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).
-
事由 %reason による %sinkWritePromise の`却下-時$には: ◎ Upon rejection of sinkWritePromise with reason,
- ~IF[ %stream.`state$wS ~EQ `writable^l ] ⇒ ~NOABRUPT `WritableStreamDefaultControllerClearAlgorithms$A( %controller ) ◎ If stream.[[state]] is "writable", perform ! WritableStreamDefaultControllerClearAlgorithms(controller).
- ~NOABRUPT `WritableStreamFinishInFlightWriteWithError$A( %stream, %reason ) ◎ Perform ! WritableStreamFinishInFlightWriteWithError(stream, reason).
-
`WritableStreamDefaultControllerWrite(controller, chunk, chunkSize)@A は、次の手続きを遂行する: ◎ WritableStreamDefaultControllerWrite(controller, chunk, chunkSize) performs the following steps:
- %enqueueResult ~LET `EnqueueValueWithSize$A( %controller, %chunk, %chunkSize ) ◎ Let enqueueResult be EnqueueValueWithSize(controller, chunk, chunkSize).
-
~IF[ %enqueueResult は`中途完了^である ]: ◎ If enqueueResult is an abrupt completion,
- ~NOABRUPT `WritableStreamDefaultControllerErrorIfNeeded$A( %controller, %enqueueResult.`Value^sl ) ◎ Perform ! WritableStreamDefaultControllerErrorIfNeeded(controller, enqueueResult.[[Value]]).
- ~RET ◎ Return.
- %stream ~LET %controller.`stream$wsdC ◎ Let stream be controller.[[stream]].
-
~IF[ ~NOABRUPT `WritableStreamCloseQueuedOrInFlight$A( %stream ) ~EQ ~F ]~AND[ %stream.`state$wS ~EQ `writable^l ] : ◎ If ! WritableStreamCloseQueuedOrInFlight(stream) is false and stream.[[state]] is "writable",
- %backpressure ~LET ~NOABRUPT `WritableStreamDefaultControllerGetBackpressure$A( %controller ) ◎ Let backpressure be ! WritableStreamDefaultControllerGetBackpressure(controller).
- ~NOABRUPT `WritableStreamUpdateBackpressure$A( %stream, %backpressure ) ◎ Perform ! WritableStreamUpdateBackpressure(stream, backpressure).
- ~NOABRUPT `WritableStreamDefaultControllerAdvanceQueueIfNeeded$A( %controller ) ◎ Perform ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).
6. 形式変換~stream
6.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【!All data successfully transformed!】)) .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);
`恒等変換~stream$には、 可読~streamと可書~streamとの間を容易に変換する利用がある。 例えば `fetch()$m ~APIは,`要請~本体$を可読~streamとして受容するが、 可書~stream~interfaceを介して~upload用の~dataを書込めれば,もっと簡便になる。 恒等変換~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();
恒等変換~streamの別の利用は、 追加的な~bufferingを`~pipe$【!`~pipe$RS】に追加することである。 この例では、 %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);
6.2. `TransformStream^I ~class
`TransformStream$I ~classは、 `形式変換~stream$の一般~概念の具象-~instanceを成す。 ◎ The TransformStream class is a concrete instance of the general transform stream concept.
6.2.1. ~interface定義
`TransformStream$I ~class用の~Web~IDL定義は: ◎ The Web IDL definition for the TransformStream class is given as follows:
[`Exposed$=*, `Transferable$] interface `TransformStream@I { `TransformStream$mc(optional `object$ %transformer, optional `QueuingStrategy$I %writableStrategy = {}, optional `QueuingStrategy$I %readableStrategy = {}); readonly attribute `ReadableStream$I `readable$ts; readonly attribute `WritableStream$I `writable$ts; };
6.2.2. 内部~slot
`TransformStream$I の各~instanceは、 次に挙げる内部~slotを伴って作成される — 各項に与える記述は`規範的でない^em: ◎ Instances of TransformStream are created with the internal slots described in the following table: ◎ Internal Slot|Description (non-normative)
- `backpressure@tS
- 【 真偽-~flag (または `undefined^jv ) 】
- 最後に観測された時点で `readable$tS 上に背圧があったかどうかを指示する。 ◎ Whether there was backpressure on [[readable]] the last time it was observed
- `backpressureChangePromise@tS
- ある~promise ◎ A promise\
- `backpressure$tS の値が変更されるたびに,充足され, 置換される。 ◎ which is fulfilled and replaced every time the value of [[backpressure]] changes
- `controller@tS
- ある `TransformStreamDefaultController$I ◎ A TransformStreamDefaultController\
- [ `readable$tS, `writable$tS ]を制御する能を伴って作成される。 ◎ created with the ability to control [[readable]] and [[writable]]
- `Detached@tS
- 真偽-~flag ◎ A boolean flag\
- この~streamが転送されたとき, ~T に設定される。 ◎ set to true when the stream is transferred
- `readable@tS
- ある `ReadableStream$I ◎ The ReadableStream instance\
- この~objにより制御される`可読~stream$。 ◎ controlled by this object
- `writable@tS
- ある `WritableStream$I ◎ The WritableStream instance\
- この~objにより制御される`可書~stream$。 ◎ controlled by this object
6.2.3. 形式変換器~API
`new TransformStream()$m 構築子は、 1 個目の引数に[ `形式変換器$を表現している~JS~obj ]を受容する。 そのような~objには、 次に挙げる~method【~callback】を包含させられる: ◎ The TransformStream() constructor accepts as its first argument a JavaScript object representing the transformer. Such objects can contain any of the following methods:
dictionary `Transformer@I { `TransformerStartCallback$I `start$tf; `TransformerTransformCallback$I `transform$tf; `TransformerFlushCallback$I `flush$tf; `TransformerCancelCallback$I `cancel$tf; `any$ `readableType$tf; `any$ `writableType$tf; }; callback `TransformerStartCallback@I = `any$ (`TransformStreamDefaultController$I %controller); callback `TransformerFlushCallback@I = `Promise$<`undefined$> (`TransformStreamDefaultController$I %controller); callback `TransformerTransformCallback@I = `Promise$<`undefined$> (`any$ %chunk, `TransformStreamDefaultController$I %controller); callback `TransformerCancelCallback@I = `Promise$<`undefined$> (`any$ %reason);
- `start(controller)@tf ( `TransformerStartCallback$I 型) ◎ start(controller), of type TransformerStartCallback
- この関数は、 `TransformStream$I を作成する間に即時に~callされる。 ◎ A function that is called immediately during creation of the TransformStream.
-
これは概して、[
%controller.`enqueue()$tsdc
を利用して,接頭-`~chunk$を~enqueueする ]ために利用される。 それらの~chunkは、 `可読~側$から読取られるが,`可書~側$へのどの書込nにも依存しないことになる。 ◎ 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. - この処理nが非同期的になる場合 — 例えば、 接頭-~chunkたちを獲得するのに 多少の労が~~要るために — この関数は,成否を通達する~promiseを返すようにすることもできる: 却下される~promiseは、 ~streamを~errorにすることになる。 投出された例外は、 `new TransformStream()$m 構築子により投出し直されることになる。 ◎ 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 ( `TransformerTransformCallback$I 型) ◎ transform(chunk, controller), of type TransformerTransformCallback
- この関数は、[ 元々は`可書~側$に書込まれた新たな`~chunk$が,形式変換~用に準備済みになった ]とき,~callされる。 ~stream実装は、 次を保証する ⇒ この関数は、 以前の形式変換が成功した後に限り~callされ,[ `start()$tf が完了する前 / `flush()$tf が~callされた後 ]には決して~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$secでは、 ときどき 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. § 10.9 A transform stream that replaces template tags demonstrates this by sometimes enqueuing zero chunks. - 形式変換~処理nが非同期的になる場合、 この関数は,形式変換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.
- この関数から返され得る~promiseは、[ `きちんと挙動する@#write-mutable-chunks$`生産器$が,`~chunk$を — それが全部的に形式変換される前に — 変異させるよう試みない ]ことを確保するため利用される。 (仕様には、 これを保証する機構は無い — それは、 `生産器$と`形式変換器$の間における非正式な契約である。) ◎ The promise potentially returned by this function is used to ensure that well-behaved producers do not attempt to mutate the chunk before it has been fully transformed. (This is not guaranteed by any specification machinery, but instead is an informal contract between producers and the transformer.)
- `transform()$tf ~methodが給されなかった場合、 恒等変換が利用される — それは、 可書~側からの~chunkをそのまま可読~側に~enqueueする。 ◎ If no transform() method is supplied, the identity transform is used, which enqueues chunks unchanged from the writable side to the readable side.
- `flush(controller)@tf ( `TransformerFlushCallback$I 型) ◎ flush(controller), of type TransformerFlushCallback
- この関数は、[ `可書~側$にすべての`~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$secに見れる。 ◎ Typically this is used to enqueue suffix chunks to the readable side, before that too becomes closed. An example can be seen in § 10.9 A transform stream that replaces template tags.
-
この書出し処理nが非同期的になる場合、
この関数は,成否を通達する~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し終える処理nにあり、 それを終了するのは非生産的になる)。 ◎ (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.) - `cancel(reason)@tf ( `TransformerCancelCallback$I 型) ◎ cancel(reason), of type TransformerCancelCallback
- この関数は、[ `可書~側$が取消された/`可書~側$が中止された ]とき,~callされる。 ◎ A function called when the readable side is cancelled, or when the writable side is aborted.
- 概して,これは、 当の~streamが[ 中止された/取消された ]ときに,下層の形式変換器~用の資源を片付けるために利用される。 ◎ Typically this is used to clean up underlying transformer resources when the stream is aborted or cancelled.
- 取消n処理nが非同期的である場合、 この関数は,その成否を通達する~promiseを返すようにすることもできる — その結果は、[ `abort()$ws / `cancel()$rs ]の~call元へ通信されることになる。 例外を投出した場合、 却下される~promiseを返すのと同じに扱われる。 ◎ If the cancellation 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.abort() or stream.readable.cancel(). Throwing an exception is treated the same as returning a rejected promise.
- ( `cancel()$tf の内側では、 `terminate()$tsdc を~callする必要は無いことに注意 — 当の~streamは,すでに[ 取消す/中止する ]処理nにあり、 それを終了するのは非生産的になる。) ◎ (Note that there is no need to call controller.terminate() inside cancel(); the stream is already in the process of cancelling/aborting, and terminating it would be counterproductive.)
- `readableType@tf ( `any$I 型) ◎ readableType, of type any
- この~propは,将来の利用-用に予約されており、 値を給するどの試みに対しても,例外を投出することになる。 ◎ This property is reserved for future use, so any attempts to supply a value will throw an exception.
- `writableType@tf ( `any$I 型) ◎ writableType, of type any
- この~propは,将来の利用-用に予約されており、 値を給するどの試みに対しても,例外を投出することになる。 ◎ This property is reserved for future use, so any attempts to supply a value will throw an exception.
[ `start()$tf / `transform()$tf / `flush()$tf ]に渡される %controller ~objは、 `TransformStreamDefaultController$I の~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.
6.2.4. 構築子, ~prop
- %stream = `new TransformStream([transformer[, writableStrategy[, readableStrategy]]])$m
- 供された`形式変換器$を包装している新たな `TransformStream$I を作成する。 %transformer 引数についての詳細は、 `形式変換器~API$secを見よ。 ◎ Creates a new TransformStream wrapping the provided transformer. See § 6.2.3 The transformer API for more details on the transformer argument.
- %transformer 引数が給されなかった場合、 結果は`恒等変換~stream$になる。 それが有用になり得る事例は、 `この例@#example-transform-identity$を見よ。 ◎ If no transformer argument is supplied, then the result will be an identity transform stream. See this example for some cases where that can be useful.
- [ %writableStrategy / %readableStrategy ]引数(以下同順)は[ 可書~側/可読~側 ]用の`~queuing策$~objを与える。 これらは,[ `WritableStream$I / `ReadableStream$I ]~objの構築に利用され、[[ 形式変換nを円滑に変速したり, `~pipe$【!`~pipe$RS】内に~bufferする量を増やす ]ために, `TransformStream$I に~bufferingを追加する ]ときにも利用され得る。 それぞれ,供されなかった場合の既定の挙動は、 `限界水位$[ 1 / 0 ]にされた `CountQueuingStrategy$I と同じになる。 ◎ 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.
- %readable = %stream.`readable$ts
- この形式変換~streamの`可読~側$を表現している `ReadableStream$I を返す。 ◎ Returns a ReadableStream representing the readable side of this transform stream.
- %writable = %stream.`writable$ts
- この形式変換~streamの`可書~側$を表現している `WritableStream$I を返す。 ◎ Returns a WritableStream representing the writable side of this transform stream.
`new TransformStream(transformer, writableStrategy, readableStrategy)@m 構築子~手続きは: ◎ The new TransformStream(transformer, writableStrategy, readableStrategy) constructor steps are:
- ~IF[ %transformer ~EQ ε ] ⇒ %transformer ~SET ~NULL ◎ If transformer is missing, set it to null.
-
%transformerDict ~LET `~IDL値に変換する$( %transformer, `Transformer$I ) ◎ Let transformerDict be transformer, converted to an IDL value of type Transformer.
注記: %transformer 引数を `Transformer$I 型として直に宣言できないのは、 元の~objへの参照が失われるからである。 ~obj上の各種`~methodを呼出せる$よう,~objは維持する必要がある。 ◎ We cannot declare the transformer argument as having the Transformer type directly, because doing so would lose the reference to the original object. We need to retain the object so we can invoke the various methods on it.
- ~IF[ %transformerDict[ "`readableType$tf" ] ~NEQ ε ] ⇒ ~THROW `RangeError$E ◎ If transformerDict["readableType"] exists, throw a RangeError exception.
- ~IF[ %transformerDict[ "`writableType$tf" ] ~NEQ ε ] ⇒ ~THROW `RangeError$E ◎ If transformerDict["writableType"] exists, throw a RangeError exception.
- %readableHighWaterMark ~LET ~ABRUPT `ExtractHighWaterMark$A( %readableStrategy, 0) ◎ Let readableHighWaterMark be ? ExtractHighWaterMark(readableStrategy, 0).
- %readableSizeAlgorithm ~LET ~NOABRUPT `ExtractSizeAlgorithm$A( %readableStrategy ) ◎ Let readableSizeAlgorithm be ! ExtractSizeAlgorithm(readableStrategy).
- %writableHighWaterMark ~LET ~ABRUPT `ExtractHighWaterMark$A( %writableStrategy, 1) ◎ Let writableHighWaterMark be ? ExtractHighWaterMark(writableStrategy, 1).
- %writableSizeAlgorithm ~LET ~NOABRUPT `ExtractSizeAlgorithm$A( %writableStrategy ) ◎ Let writableSizeAlgorithm be ! ExtractSizeAlgorithm(writableStrategy).
- %startPromise ~LET `新たな~promise$ ◎ Let startPromise be a new promise.
- ~NOABRUPT `InitializeTransformStream$A( ↓ ) ⇒# コレ, %startPromise, %writableHighWaterMark, %writableSizeAlgorithm, %readableHighWaterMark, %readableSizeAlgorithm ◎ Perform ! InitializeTransformStream(this, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm).
- ~ABRUPT `SetUpTransformStreamDefaultControllerFromTransformer$A( コレ, %transformer, %transformerDict ) ◎ Perform ? SetUpTransformStreamDefaultControllerFromTransformer(this, transformer, transformerDict).
- %結果 ~LET `undefined^jv ◎ ↓
- ~IF[ %transformerDict[ "`start$tf" ] ~NEQ ε ] ⇒ %結果 ~SET `~callback関数を呼出す$( %transformerDict[ "`start$tf" ], « コレ.`controller$tS », ε, %transformer ) ◎ If transformerDict["start"] exists, then resolve startPromise with the result of invoking transformerDict["start"] with argument list « this.[[controller]] » and callback this value transformer.
- `~promiseを解決する$( %startPromise, %結果 ) ◎ Otherwise, resolve startPromise with undefined.
`readable@ts 取得子~手続きは: ◎ The readable getter steps are:
- ~RET コレ.`readable$tS ◎ Return this.[[readable]].
`writable@ts 取得子~手続きは: ◎ The writable getter steps are:
- ~RET コレ.`writable$tS ◎ Return this.[[writable]].
6.2.5. `postMessage()^m を介する転送
%destination.postMessage(%ts, { transfer: [%ts] });
- `TransformStream$I を別の[ ~frame/~window/~worker ]へ送信する。 ◎ Sends a TransformStream to another frame, window, or worker.
- 転送された~streamは、 元の~streamとまったく同じに利用できる。 以降,その[ `可読~側$, `可書~側$ ]は どちらも`~lock$され,利用-不能になる。 ◎ The transferred stream can be used exactly like the original. Its readable and writable sides will become locked and no longer directly usable.
`TransformStream$I ~objは、 `転送-可能$である: ◎ TransformStream objects are transferable objects.\
-
その`転送-手続き$は、 所与の ( %値, %~data保持体 ) に対し: ◎ Their transfer steps, given value and dataHolder, are:
- %readable ~LET %値.`readable$tS ◎ Let readable be value.[[readable]].
- %writable ~LET %値.`writable$tS ◎ Let writable be value.[[writable]].
- ~IF[ ~NOABRUPT `IsReadableStreamLocked$A( %readable ) ~EQ ~T ] ⇒ ~THROW `DataCloneError$E ◎ If ! IsReadableStreamLocked(readable) is true, throw a "DataCloneError" DOMException.
- ~IF[ ~NOABRUPT `IsWritableStreamLocked$A( %writable ) ~EQ ~T ] ⇒ ~THROW `DataCloneError$E ◎ If ! IsWritableStreamLocked(writable) is true, throw a "DataCloneError" DOMException.
- %~data保持体.`readable^sl ~SET ~NOABRUPT `StructuredSerializeWithTransfer$A( %readable, « %readable » ) ◎ Set dataHolder.[[readable]] to ! StructuredSerializeWithTransfer(readable, « readable »).
- %~data保持体.`writable^sl ~SET ~NOABRUPT `StructuredSerializeWithTransfer$A( %writable, « %writable » ) ◎ Set dataHolder.[[writable]] to ! StructuredSerializeWithTransfer(writable, « writable »).
-
その`転送-受信-時の手続き$は、 所与の ( %~data保持体, %値 ) に対し: ◎ Their transfer-receiving steps, given dataHolder and value, are:
- %readableRecord ~LET ~NOABRUPT `StructuredDeserializeWithTransfer$A( %~data保持体.`readable^sl, `現在の~realm$ ) ◎ Let readableRecord be ! StructuredDeserializeWithTransfer(dataHolder.[[readable]], the current Realm).
- %writableRecord ~LET ~NOABRUPT `StructuredDeserializeWithTransfer$A( %~data保持体.`writable^sl, `現在の~realm$ ) ◎ Let writableRecord be ! StructuredDeserializeWithTransfer(dataHolder.[[writable]], the current Realm).
- %値 の ⇒# .`readable$tS ~SET %readableRecord.`Deserialized^sl, .`writable$tS ~SET %writableRecord.`Deserialized^sl, .`backpressure$tS ~SET `undefined^jv, .`backpressureChangePromise$tS ~SET `undefined^jv, .`controller$tS ~SET `undefined^jv ◎ Set value.[[readable]] to readableRecord.[[Deserialized]]. ◎ Set value.[[writable]] to writableRecord.[[Deserialized]]. ◎ Set value.[[backpressure]], value.[[backpressureChangePromise]], and value.[[controller]] to undefined.
注記: [ `backpressure$tS, `backpressureChangePromise$tS, `controller$tS ]~slotは、 転送された `TransformStream$I 内では,利用されない。 ◎ The [[backpressure]], [[backpressureChangePromise]], and [[controller]] slots are not used in a transferred TransformStream.
6.3. `TransformStreamDefaultController^I ~class
`TransformStreamDefaultController$I ~classは、 それに結付けられた[ `ReadableStream$I / `WritableStream$I ]の操作を許容する~methodを備える。 `TransformStream$I を構築するとき、 `形式変換器$~objには,対応する `TransformStreamDefaultController$I ~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.
6.3.1. ~interface定義
`TransformStreamDefaultController$I ~class用の~Web~IDL定義は: ◎ The Web IDL definition for the TransformStreamDefaultController class is given as follows:
[`Exposed$=*] interface `TransformStreamDefaultController@I { readonly attribute `unrestricted double$? `desiredSize$tsdc; `undefined$ `enqueue$tsdc(optional `any$ %chunk); `undefined$ `error$tsdc(optional `any$ %reason); `undefined$ `terminate$tsdc(); };
6.3.2. 内部~slot
`TransformStreamDefaultController$I の各~instanceは、 次に挙げる内部~slotを伴って作成される — 各項に与える記述は`規範的でない^em: ◎ Instances of TransformStreamDefaultController are created with the internal slots described in the following table: ◎ Internal Slot|Description (non-normative)
- `cancelAlgorithm@tsdC
- 1 個の引数(取消n用の事由)をとり,~promiseを返す~algo ◎ A promise-returning algorithm, taking one argument (the reason for cancellation),\
- 要請された取消nを当の`形式変換器$へ通信する。 ◎ which communicates a requested cancellation to the transformer
- `finishPromise@tsdC
- [ `cancelAlgorithm$tsdC / `flushAlgorithm$tsdC ]の完了に際して解決される~promise。 ◎ A promise which resolves on completion of either the [[cancelAlgorithm]] or the [[flushAlgorithm]].\
- この~fieldが `undefined^jv をとる場合、 それらの~algoはどちらも, まだ`呼出されて@~WEBIDLjs#invoke-a-callback-function$ない ◎ If this field is unpopulated (that is, undefined), then neither of those algorithms have been invoked yet
- `flushAlgorithm@tsdC
- ~promiseを返す~algo ◎ A promise-returning algorithm\
- 要請された~closeを当の`形式変換器$へ通信する。 ◎ which communicates a requested close to the transformer
- `stream@tsdC
- ある `TransformStream$I ◎ ↓
- この制御器により制御される`形式変換~stream$。 ◎ The TransformStream instance controlled
- `transformAlgorithm@tsdC
- 1 個の引数(形式変換への`~chunk$)をとり,~promiseを返す~algo ◎ A promise-returning algorithm, taking one argument (the chunk to transform),\
- 当の`形式変換器$に形式変換nを遂行するよう要請する。 ◎ which requests the transformer perform its transformation
6.3.3. ~method/~prop
- %desiredSize = %controller.`desiredSize$tsdc
- `~streamの内部~queueの残り~size$を返す。 それは、 負になり得る — ~queueが溢れた場合に。 ◎ Returns the desired size to fill the readable side’s internal queue. It can be negative, if the queue is over-full.
- %controller.`enqueue(chunk)$tsdc
- 所与の`~chunk$ %chunk を制御先の形式変換~streamの`可読~側$に~enqueueする。 ◎ Enqueues the given chunk chunk in the readable side of the controlled transform stream.
- %controller.`error(e)$tsdc
- 制御先の`形式変換~stream$の[ `可読~側$, `可書~側$ ]どちらも~errorにする — 以降のヤリトリは、 すべて所与の~error %e で失敗し, 形式変換n用に~queueされたどの`~chunk$も破棄されることになる。 ◎ Errors both the readable side and the writable side of the controlled transform stream, making all future interactions with it fail with the given error e. Any chunks queued for transformation will be discarded.
- %controller.`terminate()$tsdc
- 制御先の`形式変換~stream$の`可読~側$を~closeして, `可書~側$を~errorにする。 これは、 `形式変換器$が[ `可書~側$に書込まれた`~chunk$たちの一部分だけ消費する必要がある ]ときに有用になる。 ◎ Closes the readable side and errors 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.
`desiredSize@tsdc 取得子~手続きは: ◎ The desiredSize getter steps are:
- %readableController ~LET コレ.`stream$tsdC.`readable$tS.`controller$rS ◎ Let readableController be this.[[stream]].[[readable]].[[controller]].
- ~RET ~NOABRUPT `ReadableStreamDefaultControllerGetDesiredSize$A( %readableController ) ◎ Return ! ReadableStreamDefaultControllerGetDesiredSize(readableController).
`enqueue(chunk)@tsdc ~method手続きは: ◎ The enqueue(chunk) method steps are:
- ~ABRUPT `TransformStreamDefaultControllerEnqueue$A( コレ, %chunk ) ◎ Perform ? TransformStreamDefaultControllerEnqueue(this, chunk).
`error(e)@tsdc ~method手続きは: ◎ The error(e) method steps are:
- ~ABRUPT `TransformStreamDefaultControllerError$A( コレ, %e ) ◎ Perform ? TransformStreamDefaultControllerError(this, e).
`terminate()@tsdc ~method手続きは: ◎ The terminate() method steps are:
- ~ABRUPT `TransformStreamDefaultControllerTerminate$A( コレ ) ◎ Perform ? TransformStreamDefaultControllerTerminate(this).
6.4. 抽象-演算
6.4.1. 形式変換~streamとの作業-法
以下に与える抽象-演算は、 `TransformStream$I ~instanceに対し高~levelから演算する。 ◎ The following abstract operations operate on TransformStream instances at a higher level.
`InitializeTransformStream(stream, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm)@A は、次の手続きを遂行する: ◎ InitializeTransformStream(stream, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm) performs the following steps:
- %startAlgorithm ~LET 次を走らす~algo ⇒ ~RET %startPromise ◎ Let startAlgorithm be an algorithm that returns startPromise.
- %writeAlgorithm ~LET 所与の ( %chunk ) に対し,次を走らす~algo ⇒ ~RET ~NOABRUPT `TransformStreamDefaultSinkWriteAlgorithm$A( %stream, %chunk ) ◎ Let writeAlgorithm be the following steps, taking a chunk argument: • Return ! TransformStreamDefaultSinkWriteAlgorithm(stream, chunk).
- %abortAlgorithm ~LET 所与の ( %reason ) に対し,次を走らす~algo ⇒ ~RET ~NOABRUPT `TransformStreamDefaultSinkAbortAlgorithm$A( %stream, %reason ) ◎ Let abortAlgorithm be the following steps, taking a reason argument: • Return ! TransformStreamDefaultSinkAbortAlgorithm(stream, reason).
- %closeAlgorithm ~LET 次を走らす~algo ⇒ ~RET ~NOABRUPT `TransformStreamDefaultSinkCloseAlgorithm$A( %stream ) ◎ Let closeAlgorithm be the following steps: • Return ! TransformStreamDefaultSinkCloseAlgorithm(stream).
- %stream.`writable$tS ~SET ~NOABRUPT `CreateWritableStream$A( %startAlgorithm, %writeAlgorithm, %closeAlgorithm, %abortAlgorithm, %writableHighWaterMark, %writableSizeAlgorithm ) ◎ Set stream.[[writable]] to ! CreateWritableStream(startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, writableHighWaterMark, writableSizeAlgorithm).
- %pullAlgorithm ~LET 次を走らす~algo ⇒ ~RET ~NOABRUPT `TransformStreamDefaultSourcePullAlgorithm$A( %stream ) ◎ Let pullAlgorithm be the following steps: • Return ! TransformStreamDefaultSourcePullAlgorithm(stream).
- %cancelAlgorithm ~LET 所与の ( %reason ) に対し,次を走らす~algo ⇒ ~RET ~NOABRUPT `TransformStreamDefaultSourceCancelAlgorithm$A( %stream, %reason ) ◎ Let cancelAlgorithm be the following steps, taking a reason argument: • Return ! TransformStreamDefaultSourceCancelAlgorithm(stream, reason).
- %stream.`readable$tS ~SET ~NOABRUPT `CreateReadableStream$A( %startAlgorithm, %pullAlgorithm, %cancelAlgorithm, %readableHighWaterMark, %readableSizeAlgorithm ) ◎ Set stream.[[readable]] to ! CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm, readableHighWaterMark, readableSizeAlgorithm).
-
%stream の ⇒# .`backpressure$tS ~SET `undefined^jv, .`backpressureChangePromise$tS ~SET `undefined^jv ◎ Set stream.[[backpressure]] and stream.[[backpressureChangePromise]] to undefined.
注記: `backpressure$tS ~slotは、 `TransformStreamSetBackpressure$A により初期化できるよう, `undefined^jv に設定される。 別法として,実装は、 `backpressure$tS 用に厳密な真偽-値を利用して,初期化される仕方を変更できる。 これは、 初期化が[ 当の形式変換器の `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 the transformer’s start() method is called.
- ~NOABRUPT `TransformStreamSetBackpressure$A( %stream, ~T ) ◎ Perform ! TransformStreamSetBackpressure(stream, true).
- %stream.`controller$tS ~SET `undefined^jv ◎ Set stream.[[controller]] to undefined.
`TransformStreamError(stream, e)@A は、次の手続きを遂行する: ◎ TransformStreamError(stream, e) performs the following steps:
- ~NOABRUPT `ReadableStreamDefaultControllerError$A( %stream.`readable$tS.`controller$rS, %e ) ◎ Perform ! ReadableStreamDefaultControllerError(stream.[[readable]].[[controller]], e).
- ~NOABRUPT `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.
`TransformStreamErrorWritableAndUnblockWrite(stream, e)@A は、次の手続きを遂行する: ◎ TransformStreamErrorWritableAndUnblockWrite(stream, e) performs the following steps:
- ~NOABRUPT `TransformStreamDefaultControllerClearAlgorithms$A( %stream.`controller$tS) ◎ Perform ! TransformStreamDefaultControllerClearAlgorithms(stream.[[controller]]).
- ~NOABRUPT `WritableStreamDefaultControllerErrorIfNeeded$A( %stream.`writable$tS.`controller$wS, %e ) ◎ Perform ! WritableStreamDefaultControllerErrorIfNeeded(stream.[[writable]].[[controller]], e).
- ~NOABRUPT `TransformStreamUnblockWrite$A( %stream ) ◎ Perform ! TransformStreamUnblockWrite(stream).
`TransformStreamSetBackpressure(stream, backpressure)@A は、次の手続きを遂行する: ◎ TransformStreamSetBackpressure(stream, backpressure) performs the following steps:
- ~Assert: %stream.`backpressure$tS ~NEQ %backpressure ◎ Assert: stream.[[backpressure]] is not backpressure.
- ~IF[ %stream.`backpressureChangePromise$tS ~NEQ `undefined^jv ] ⇒ `~promiseを解決する$( %stream.`backpressureChangePromise$tS, `undefined^jv ) ◎ If stream.[[backpressureChangePromise]] is not undefined, resolve stream.[[backpressureChangePromise]] with undefined.
- %stream.`backpressureChangePromise$tS ~SET `新たな~promise$ ◎ Set stream.[[backpressureChangePromise]] to a new promise.
- %stream.`backpressure$tS ~SET %backpressure ◎ Set stream.[[backpressure]] to backpressure.
`TransformStreamUnblockWrite@A は、次の手続きを遂行する: ◎ TransformStreamUnblockWrite(stream) performs the following steps:
- ~IF[ %stream.`backpressure$tS ~EQ ~T ] ⇒ ~NOABRUPT `TransformStreamSetBackpressure$A( %stream, ~F ) ◎ If stream.[[backpressure]] is true, perform ! TransformStreamSetBackpressure(stream, false).
注記: `TransformStreamDefaultSinkWriteAlgorithm$A 抽象-演算は、 `backpressureChangePromise$tS ~slotに格納された~promiseが解決されるまで待機することもある。 `TransformStreamSetBackpressure$A への~callは、 ~promiseが常に解決されることを確保する。 ◎ The TransformStreamDefaultSinkWriteAlgorithm abstract operation could be waiting for the promise stored in the [[backpressureChangePromise]] slot to resolve. The call to TransformStreamSetBackpressure ensures that the promise always resolves.
6.4.2. 既定の制御器
以下に与える抽象-演算は、 `TransformStreamDefaultController$I ~classの実装を~supportする。 ◎ The following abstract operations support the implementaiton of the TransformStreamDefaultController class.
`SetUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm, cancelAlgorithm)@A は、次の手続きを遂行する: ◎ SetUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm, cancelAlgorithm) performs the following steps:
- ~Assert: %stream は `TransformStream$I を`実装する$ ◎ Assert: stream implements TransformStream.
- ~Assert: %stream.`controller$tS ~EQ `undefined^jv ◎ Assert: stream.[[controller]] is undefined.
- %controller.`stream$tsdC ~SET %stream ◎ Set controller.[[stream]] to stream.
- %stream.`controller$tS ~SET %controller ◎ Set stream.[[controller]] to controller.
- %controller.`transformAlgorithm$tsdC ~SET %transformAlgorithm ◎ Set controller.[[transformAlgorithm]] to transformAlgorithm.
- %controller.`flushAlgorithm$tsdC ~SET %flushAlgorithm ◎ Set controller.[[flushAlgorithm]] to flushAlgorithm.
- %controller.`cancelAlgorithm$tsdC ~SET %cancelAlgorithm ◎ Set controller.[[cancelAlgorithm]] to cancelAlgorithm.
`SetUpTransformStreamDefaultControllerFromTransformer(stream, transformer, transformerDict)@A は、次の手続きを遂行する: ◎ SetUpTransformStreamDefaultControllerFromTransformer(stream, transformer, transformerDict) performs the following steps:
- %controller ~LET `新たな$ `TransformStreamDefaultController$I ◎ Let controller be a new TransformStreamDefaultController.
-
%transformAlgorithm ~LET 所与の ( %chunk ) に対し,次を走らす~algo: ◎ 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 `却下される~promise$( %result.`Value^sl ) ◎ If result is an abrupt completion, return a promise rejected with result.[[Value]].
- ~RET `解決される~promise$( `undefined^jv ) ◎ Otherwise, return a promise resolved with undefined.
- %flushAlgorithm ~LET 次を走らす~algo ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ Let flushAlgorithm be an algorithm which returns a promise resolved with undefined.
- %cancelAlgorithm ~LET 次を走らす~algo ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ Let cancelAlgorithm be an algorithm which returns a promise resolved with undefined.
- ~IF[ %transformerDict[ "`transform$tf" ] ~NEQ ε ] ⇒ %transformAlgorithm ~SET 所与の ( %chunk ) に対し,次を走らす~algo ⇒ ~RET `~callback関数を呼出す$( %transformerDict[ "`transform$tf" ], « %chunk, %controller », ε, %transformer ) ◎ If transformerDict["transform"] exists, set transformAlgorithm to an algorithm which takes an argument chunk and returns the result of invoking transformerDict["transform"] with argument list « chunk, controller » and callback this value transformer.
- ~IF[ %transformerDict[ "`flush$tf" ] ~NEQ ε ] ⇒ %flushAlgorithm ~SET 次を走らす~algo ⇒ ~RET `~callback関数を呼出す$( %transformerDict[ "`flush$tf" ], « %controller », ε, %transformer ) ◎ If transformerDict["flush"] exists, set flushAlgorithm to an algorithm which returns the result of invoking transformerDict["flush"] with argument list « controller » and callback this value transformer.
- ~IF[ %transformerDict[ "`cancel$tf" ] ~NEQ ε ] ⇒ %cancelAlgorithm ~SET 所与の ( %reason ) に対し,次を走らす~algo ⇒ ~RET `~callback関数を呼出す$( %transformerDict[ "`cancel$tf" ], « %reason », ε, %transformer ) ◎ If transformerDict["cancel"] exists, set cancelAlgorithm to an algorithm which takes an argument reason and returns the result of invoking transformerDict["cancel"] with argument list « reason » and callback this value transformer.
- ~NOABRUPT `SetUpTransformStreamDefaultController$A( ↓ ) ⇒# %stream, %controller, %transformAlgorithm, %flushAlgorithm, %cancelAlgorithm ◎ Perform ! SetUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm, cancelAlgorithm).
`TransformStreamDefaultControllerClearAlgorithms(controller)@A は、[ ~streamが~closeされるか~errorして, 各種~algoが それ以上~実行されなくなったとき ]に~callされる。 これは、 各種~algoへの参照を除去することにより, `形式変換器$( `TransformStream$I ~obj)自身が — まだ参照されていても — ~garbage収集されることを許可する。 ◎ TransformStreamDefaultControllerClearAlgorithms(controller) 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.
注記: これは、 `弱い参照@https://github.com/tc39/proposal-weakrefs/$を利用すると観測-可能になる。 詳細は `tc39/proposal-weakrefs#31@https://github.com/tc39/proposal-weakrefs/issues/31$ を見よ。 ◎ This is observable using weak references. See tc39/proposal-weakrefs#31 for more detail.
それは、次の手続きを遂行する: ◎ It performs the following steps:
- %controller.`transformAlgorithm$tsdC ~SET `undefined^jv ◎ Set controller.[[transformAlgorithm]] to undefined.
- %controller.`flushAlgorithm$tsdC ~SET `undefined^jv ◎ Set controller.[[flushAlgorithm]] to undefined.
- %controller.`cancelAlgorithm$tsdC ~SET `undefined^jv ◎ Set controller.[[cancelAlgorithm]] to undefined.
`TransformStreamDefaultControllerEnqueue(controller, chunk)@A は、次の手続きを遂行する: ◎ TransformStreamDefaultControllerEnqueue(controller, chunk) performs the following steps:
- %stream ~LET %controller.`stream$tsdC ◎ Let stream be controller.[[stream]].
- %readableController ~LET %stream.`readable$tS.`controller$rS ◎ Let readableController be stream.[[readable]].[[controller]].
- ~IF[ ~NOABRUPT `ReadableStreamDefaultControllerCanCloseOrEnqueue$A( %readableController ) ~EQ ~F ] ⇒ ~THROW `TypeError$jE ◎ 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,
- ~NOABRUPT `TransformStreamErrorWritableAndUnblockWrite$A( %stream, %enqueueResult.`Value^sl ) ◎ Perform ! TransformStreamErrorWritableAndUnblockWrite(stream, enqueueResult.[[Value]]).
- ~THROW %stream.`readable$tS.`storedError$rS ◎ Throw stream.[[readable]].[[storedError]].
- %backpressure ~LET ~NOABRUPT `ReadableStreamDefaultControllerHasBackpressure$A( %readableController ) ◎ Let backpressure be ! ReadableStreamDefaultControllerHasBackpressure(readableController).
-
~IF[ %backpressure ~NEQ %stream.`backpressure$tS ]: ◎ If backpressure is not stream.[[backpressure]],
- ~Assert: %backpressure ~EQ ~T ◎ Assert: backpressure is true.
- ~NOABRUPT `TransformStreamSetBackpressure$A( %stream, ~T ) ◎ Perform ! TransformStreamSetBackpressure(stream, true).
`TransformStreamDefaultControllerError(controller, e)@A は、次の手続きを遂行する: ◎ TransformStreamDefaultControllerError(controller, e) performs the following steps:
- ~NOABRUPT `TransformStreamError$A( %controller.`stream$tsdC, %e ) ◎ Perform ! TransformStreamError(controller.[[stream]], e).
`TransformStreamDefaultControllerPerformTransform(controller, chunk)@A は、次の手続きを遂行する: ◎ TransformStreamDefaultControllerPerformTransform(controller, chunk) performs the following steps:
- %transformPromise ~LET %controller.`transformAlgorithm$tsdC( %chunk ) ◎ Let transformPromise be the result of performing controller.[[transformAlgorithm]], passing chunk.
-
~RET `~promiseに反応する$( %transformPromise ) — 次を与える下で: ◎ Return the result of reacting to transformPromise with\
-
`却下~手続き^i は、 所与の ( %r ) に対し: ◎ the following rejection steps given the argument r:
- ~NOABRUPT `TransformStreamError$A( %controller.`stream$tsdC, %r ) ◎ Perform ! TransformStreamError(controller.[[stream]], r).
- ~THROW %r ◎ Throw r.
-
`TransformStreamDefaultControllerTerminate(controller)@A は、次の手続きを遂行する: ◎ TransformStreamDefaultControllerTerminate(controller) performs the following steps:
- %stream ~LET %controller.`stream$tsdC ◎ Let stream be controller.[[stream]].
- %readableController ~LET %stream.`readable$tS.`controller$rS ◎ Let readableController be stream.[[readable]].[[controller]].
- ~NOABRUPT `ReadableStreamDefaultControllerClose$A( %readableController ) ◎ Perform ! ReadableStreamDefaultControllerClose(readableController).
- %error ~LET ~streamは終了されたことを指示する, `TypeError$jE 例外 ◎ Let error be a TypeError exception indicating that the stream has been terminated.
- ~NOABRUPT `TransformStreamErrorWritableAndUnblockWrite$A( %stream, %error ) ◎ Perform ! TransformStreamErrorWritableAndUnblockWrite(stream, error).
6.4.3. 既定の~sink
以下に与える抽象-演算は、 `形式変換~stream$の`可書~側$用の`下層~sink$を実装するために利用される。 ◎ The following abstract operations are used to implement the underlying sink for the writable side of transform streams.
`TransformStreamDefaultSinkWriteAlgorithm(stream, chunk)@A は、次の手続きを遂行する: ◎ TransformStreamDefaultSinkWriteAlgorithm(stream, chunk) performs the following steps:
- ~Assert: %stream.`writable$tS.`state$wS ~EQ `writable^l ◎ Assert: stream.[[writable]].[[state]] is "writable".
- %controller ~LET %stream.`controller$tS ◎ Let controller be stream.[[controller]].
-
~IF[ %stream.`backpressure$tS ~EQ ~T ]: ◎ If stream.[[backpressure]] is true,
- %backpressureChangePromise ~LET %stream.`backpressureChangePromise$tS ◎ Let backpressureChangePromise be stream.[[backpressureChangePromise]].
- ~Assert: %backpressureChangePromise ~NEQ `undefined^jv ◎ Assert: backpressureChangePromise is not undefined.
-
~RET `~promiseに反応する$( %backpressureChangePromise ) — `充足~手続き^i として次を与える下で: ◎ Return the result of reacting to backpressureChangePromise with\
-
`充足~手続き^i は: ◎ the following fulfillment steps:
- %writable ~LET %stream.`writable$tS ◎ Let writable be stream.[[writable]].
- %state ~LET %writable.`state$wS ◎ Let state be writable.[[state]].
- ~IF[ %state ~EQ `erroring^l ] ⇒ ~THROW %writable.`storedError$wS ◎ If state is "erroring", throw writable.[[storedError]].
- ~Assert: %state ~EQ `writable^l ◎ Assert: state is "writable".
- ~RET ~NOABRUPT `TransformStreamDefaultControllerPerformTransform$A( %controller, %chunk ) ◎ Return ! TransformStreamDefaultControllerPerformTransform(controller, chunk).
-
- ~RET ~NOABRUPT `TransformStreamDefaultControllerPerformTransform$A( %controller, %chunk ) ◎ Return ! TransformStreamDefaultControllerPerformTransform(controller, chunk).
`TransformStreamDefaultSinkAbortAlgorithm(stream, reason)@A は、次の手続きを遂行する: ◎ TransformStreamDefaultSinkAbortAlgorithm(stream, reason) performs the following steps:
- %controller ~LET %stream.`controller$wS ◎ Let controller be stream.[[controller]].
- ~IF[ %controller.`finishPromise$tsdC ~NEQ `undefined^jv ] ⇒ ~RET %controller.`finishPromise$tsdC ◎ If controller.[[finishPromise]] is not undefined, return controller.[[finishPromise]].
- %readable ~LET %stream.`readable$tS ◎ Let readable be stream.[[readable]].
- %controller.`finishPromise$tsdC ~LET `新たな~promise$ ◎ Let controller.[[finishPromise]] be a new promise.
- %cancelPromise ~LET %controller.`cancelAlgorithm$tsdC( %reason ) ◎ Let cancelPromise be the result of performing controller.[[cancelAlgorithm]], passing reason.
- ~NOABRUPT `TransformStreamDefaultControllerClearAlgorithms$A( %controller ) ◎ Perform ! TransformStreamDefaultControllerClearAlgorithms(controller).
-
`~promiseに反応する$( %cancelPromise ) — 次を与える下で: ◎ React to cancelPromise:
-
`充足~手続き^i は: ◎ If cancelPromise was fulfilled, then:
- ~IF[ %readable.`state$rS ~EQ `errored^l ] ⇒ `~promiseを却下する$( %controller.`finishPromise$tsdC, %readable.`storedError$rS ) ◎ If readable.[[state]] is "errored", reject controller.[[finishPromise]] with readable.[[storedError]].
-
~ELSE: ◎ Otherwise:
- ~NOABRUPT `ReadableStreamDefaultControllerError$A( %readable.`controller$rS, %reason ) ◎ Perform ! ReadableStreamDefaultControllerError(readable.[[controller]], reason).
- `~promiseを解決する$( %controller.`finishPromise$tsdC, `undefined^jv ) ◎ Resolve controller.[[finishPromise]] with undefined.
-
`却下~手続き^i は、 所与の ( 事由 %r ) に対し: ◎ If cancelPromise was rejected with reason r, then:
- ~NOABRUPT `ReadableStreamDefaultControllerError$A( %readable.`controller$rS, %r ) ◎ Perform ! ReadableStreamDefaultControllerError(readable.[[controller]], r).
- `~promiseを却下する$( %controller.`finishPromise$tsdC, %r ) ◎ Reject controller.[[finishPromise]] with r.
-
- ~RET %controller.`finishPromise$tsdC ◎ Return controller.[[finishPromise]].
`TransformStreamDefaultSinkCloseAlgorithm(stream)@A は、次の手続きを遂行する: ◎ TransformStreamDefaultSinkCloseAlgorithm(stream) performs the following steps:
- %controller ~LET %stream.`controller$wS ◎ Let controller be stream.[[controller]].
- ~IF[ %controller.`finishPromise$tsdC ~NEQ `undefined^jv ] ⇒ ~RET %controller.`finishPromise$tsdC ◎ If controller.[[finishPromise]] is not undefined, return controller.[[finishPromise]].
- %readable ~LET %stream.`readable$tS ◎ Let readable be stream.[[readable]].
- %controller.`finishPromise$tsdC ~LET `新たな~promise$ ◎ Let controller.[[finishPromise]] be a new promise.
- %flushPromise ~LET %controller.`flushAlgorithm$tsdC() ◎ Let flushPromise be the result of performing controller.[[flushAlgorithm]].
- ~NOABRUPT `TransformStreamDefaultControllerClearAlgorithms$A( %controller ) ◎ Perform ! TransformStreamDefaultControllerClearAlgorithms(controller).
-
`~promiseに反応する$( %flushPromise ) — 次を与える下で: ◎ React to flushPromise:
-
`充足~手続き^i は: ◎ If flushPromise was fulfilled, then:
- ~IF[ %readable.`state$rS ~EQ `errored^l ] ⇒ `~promiseを却下する$( %controller.`finishPromise$tsdC, %readable.`storedError$rS ) ◎ If readable.[[state]] is "errored", reject controller.[[finishPromise]] with readable.[[storedError]].
-
~ELSE: ◎ Otherwise:
- ~NOABRUPT `ReadableStreamDefaultControllerClose$A( %readable.`controller$rS ) ◎ Perform ! ReadableStreamDefaultControllerClose(readable.[[controller]]).
- `~promiseを解決する$( %controller.`finishPromise$tsdC, `undefined^jv ) ◎ Resolve controller.[[finishPromise]] with undefined.
-
`却下~手続き^i は、 所与の ( 事由 %r ) に対し: ◎ If flushPromise was rejected with reason r, then:
- ~NOABRUPT `ReadableStreamDefaultControllerError$A( %readable.`controller$rS, %r ) ◎ Perform ! ReadableStreamDefaultControllerError(readable.[[controller]], r).
- `~promiseを却下する$( %controller.`finishPromise$tsdC, %r ) ◎ Reject controller.[[finishPromise]] with r.
-
- ~RET %controller.`finishPromise$tsdC ◎ Return controller.[[finishPromise]].
6.4.4. 既定の~source
以下に与える抽象-演算は、 `形式変換~stream$の`可読~側$用の`下層~source$を実装するために利用される。 ◎ The following abstract operation is used to implement the underlying source for the readable side of transform streams.
`TransformStreamDefaultSourceCancelAlgorithm(stream, reason)@A は、 次の手続きを遂行する: ◎ TransformStreamDefaultSourceCancelAlgorithm(stream, reason) performs the following steps:
- %controller ~LET %stream.`controller$wS ◎ Let controller be stream.[[controller]].
- ~IF[ %controller.`finishPromise$tsdC ~NEQ `undefined^jv ] ⇒ ~RET %controller.`finishPromise$tsdC ◎ If controller.[[finishPromise]] is not undefined, return controller.[[finishPromise]].
- %writable ~LET %stream.`writable$tS ◎ Let writable be stream.[[writable]].
- %controller.`finishPromise$tsdC ~LET `新たな~promise$ ◎ Let controller.[[finishPromise]] be a new promise.
- %cancelPromise ~LET %controller.`cancelAlgorithm$tsdC( %reason ) ◎ Let cancelPromise be the result of performing controller.[[cancelAlgorithm]], passing reason.
- ~NOABRUPT `TransformStreamDefaultControllerClearAlgorithms$A( %controller ) ◎ Perform ! TransformStreamDefaultControllerClearAlgorithms(controller).
-
`~promiseに反応する$( %cancelPromise ) — 次を与える下で: ◎ React to cancelPromise:
-
`充足~手続き^i は: ◎ If cancelPromise was fulfilled, then:
- ~IF[ %writable.`state$wS ~EQ `errored^l ] ⇒ `~promiseを却下する$( %controller.`finishPromise$tsdC, %writable.`storedError$wS ) ◎ If writable.[[state]] is "errored", reject controller.[[finishPromise]] with writable.[[storedError]].
-
~ELSE: ◎ Otherwise:
- ~NOABRUPT `WritableStreamDefaultControllerErrorIfNeeded$A( %writable.`controller$wS, %reason ) ◎ Perform ! WritableStreamDefaultControllerErrorIfNeeded(writable.[[controller]], reason).
- ~NOABRUPT `TransformStreamUnblockWrite$A( %stream ) ◎ Perform ! TransformStreamUnblockWrite(stream).
- `~promiseを解決する$( %controller.`finishPromise$tsdC, `undefined^jv ) ◎ Resolve controller.[[finishPromise]] with undefined.
-
`却下~手続き^i は、 所与の ( 事由 %r ) に対し: ◎ If cancelPromise was rejected with reason r, then:
- ~NOABRUPT `WritableStreamDefaultControllerErrorIfNeeded$A( %writable.`controller$wS, %r ) ◎ Perform ! WritableStreamDefaultControllerErrorIfNeeded(writable.[[controller]], r).
- ~NOABRUPT `TransformStreamUnblockWrite$A( %stream ) ◎ Perform ! TransformStreamUnblockWrite(stream).
- `~promiseを却下する$( %controller.`finishPromise$tsdC, %r ) ◎ Reject controller.[[finishPromise]] with r.
-
- ~RET %controller.`finishPromise$tsdC ◎ Return controller.[[finishPromise]].
`TransformStreamDefaultSourcePullAlgorithm(stream)@A は、次の手続きを遂行する: ◎ TransformStreamDefaultSourcePullAlgorithm(stream) performs the following steps:
- ~Assert: %stream.`backpressure$tS ~EQ ~T ◎ Assert: stream.[[backpressure]] is true.
- ~Assert: %stream.`backpressureChangePromise$tS ~NEQ `undefined^jv ◎ Assert: stream.[[backpressureChangePromise]] is not undefined.
- ~NOABRUPT `TransformStreamSetBackpressure$A( %stream, ~F ) ◎ Perform ! TransformStreamSetBackpressure(stream, false).
- ~RET %stream.`backpressureChangePromise$tS ◎ Return stream.[[backpressureChangePromise]].
7. ~queuing策
7.1. ~queuing策~API
[ `new ReadableStream()$m / `new WritableStream()$m / `new TransformStream()$m ]構築子は、 どれも[ 作成されている~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:
dictionary `QueuingStrategy@I { `unrestricted double$ `highWaterMark$qs; `QueuingStrategySize$I `size$qs; }; callback `QueuingStrategySize@I = `unrestricted double$ (`any$ %chunk);
- `highWaterMark@qs ( `unrestricted double$I 型) ◎ highWaterMark, of type unrestricted double
- 負でない~number。 この~queuing策を利用している~streamの`限界水位$を指示する。 ◎ A non-negative number indicating the high water mark of the stream using this queuing strategy.
- `size(chunk)@qs (非~byte~stream用に限る) ( `QueuingStrategySize$I 型) ◎ size(chunk) (non-byte streams only), of type QueuingStrategySize
- この関数は、 所与の`~chunk$値の有限かつ負でない~sizeを算出した結果を返す。 ◎ A function that computes and returns the finite non-negative size of the given chunk value.
-
結果は、
`背圧$を決定するために利用される。
それは、
適切な `desiredSize^c ~prop
— ~queuing策がどこで利用されているかに依存して,[
%defaultController.`desiredSize$rsdc
,%byteController.`desiredSize$rbsc
,%writer.`desiredSize$dw
]のいずれか — を介して~~露わになる。 それは,可読~stream用には、 `下層~source$の `pull()$usc ~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.
~queuing策~objが期待される所では、 これらの~propを伴うどの~objも利用できる。 しかしながら,ある種の事例~用に共通的な語彙を供するためとして、 組込みの~queuing策~class — `ByteLengthQueuingStrategy$I, `CountQueuingStrategy$I — も供される。 どちらも,その構築子~用に次の~Web~IDL片を用立てる: ◎ 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. They both make use of the following Web IDL fragment for their constructors:
dictionary `QueuingStrategyInit@I { required `unrestricted double$ `highWaterMark@qsi; };
7.2. `ByteLengthQueuingStrategy^I ~class
~byte列を~~扱うときに共通的な`~queuing策$は、[ 流入ng`~chunk$たちの `byteLength^c ~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実装が下層~sourceへ`背圧$通達の送信を開始するまで ]に, 可読~streamの`下層~source$に~~総計 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 }) );
この事例では、[ `下層~sink$への以前の書込nが完遂するまで待機する間, 可書~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$I の利用は必要yでない — その~chunk数は常に~byte数で測定されるので。 `ByteLengthQueuingStrategy$I で~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.
7.2.1. ~interface定義
`ByteLengthQueuingStrategy$I ~class用の~Web~IDL定義は: ◎ The Web IDL definition for the ByteLengthQueuingStrategy class is given as follows:
[`Exposed$=*] interface `ByteLengthQueuingStrategy@I { `ByteLengthQueuingStrategy$mc(`QueuingStrategyInit$I %init); readonly attribute `unrestricted double$ `highWaterMark$blqs; readonly attribute `Function$I `size$blqs; };
7.2.2. 内部~slot
`ByteLengthQueuingStrategy$I の各~instanceには, `highWaterMark@blQS 内部~slotがあり,構築子に与えられた値を格納する。 ◎ Instances of ByteLengthQueuingStrategy have a [[highWaterMark]] internal slot, storing the value given in the constructor.
加えて,どの`大域~obj$ %大域~obj にも `~byte長さ~queuing策~size関数@ が結付けられる。 その値は `Function$I であり、 次に従って初期化するモノトスル: ◎ Additionally, every global object globalObject has an associated byte length queuing strategy size function, which is a Function whose value must be initialized as follows:
- %手続き ~LET 所与の ( %chunk ) に対し,次を走らす~algo ⇒ ~RET ~ABRUPT `GetV$Ax( %chunk, `byteLength^l ) ◎ Let steps be the following steps, given chunk: • Return ? GetV(chunk, "byteLength").
- %F ~LET ~NOABRUPT `CreateBuiltinFunction$Ax( %手続き, 1, `size^l, « », %大域~obj に`関連な~realm$ ) ◎ Let F be ! CreateBuiltinFunction(steps, 1, "size", « », globalObject’s relevant Realm).
- %大域~obj の`~byte長さ~queuing策~size関数$ ~SET %F への参照を表現する `Function$I — その`~callback文脈$は、 %大域~obj に`関連な設定群~obj$になるとする ◎ Set globalObject’s byte length queuing strategy size function to a Function that represents a reference to F, with callback context equal to globalObject’s relevant settings object.
注記: この設計は、 いくぶん歴史的である。 その動機は、 `size$blqs は関数であって~methodではない — すなわち,その `this^jv 値を検査しない — ことを確保するよう欲されることにある。 更なる背景0は、 `課題 #1005@https://github.com/whatwg/streams/issues/1005$, `whatwg/webidl 課題 #819@https://github.com/whatwg/webidl/issues/819$ を見よ。 ◎ This design is somewhat historical. It is motivated by the desire to ensure that size is a function, not a method, i.e. it does not check its this value. See whatwg/streams#1005 and heycam/webidl#819 for more background.
7.2.3. 構築子, ~prop
- %strategy = `new ByteLengthQueuingStrategy$m({ `highWaterMark$qsi })
- 供された`限界水位$を伴う新たな `ByteLengthQueuingStrategy$I を作成する。 ◎ Creates a new ByteLengthQueuingStrategy with the provided high water mark.
- 供された`限界水位$は、 事前に検証されないことに注意。 それが[ ~numberでない/ `NaN^jv または負な~numberである ]場合、 結果の `ByteLengthQueuingStrategy$I は, 対応する~stream構築子にて例外を投出させることになる。 ◎ Note that the provided high water mark will not be validated ahead of time. Instead, if it is negative, NaN, or not a number, the resulting ByteLengthQueuingStrategy will cause the corresponding stream constructor to throw.
- %highWaterMark = %strategy.`highWaterMark$blqs
- 構築子に供された`限界水位$を返す。 ◎ Returns the high water mark provided to the constructor.
- %strategy.`size(chunk)$blqs
- `byteLength^c ~propの値を返すことにより, %chunk の~sizeを測定する。 ◎ Measures the size of chunk by returning the value of its byteLength property.
`new ByteLengthQueuingStrategy(init)@m 構築子~手続きは: ◎ The new ByteLengthQueuingStrategy(init) constructor steps are:
- コレ.`highWaterMark$blQS ~SET %init[ "`highWaterMark$qsi" ] ◎ Set this.[[highWaterMark]] to init["highWaterMark"].
`highWaterMark@blqs 取得子~手続きは: ◎ The highWaterMark getter steps are:
- ~RET コレ.`highWaterMark$blQS ◎ Return this.[[highWaterMark]].
`size@blqs 取得子~手続きは: ◎ The size getter steps are:
- ~RET コレに`関連な大域~obj$の`~byte長さ~queuing策~size関数$ 。 ◎ Return this's relevant global object's byte length queuing strategy size function.
7.3. `CountQueuingStrategy^I ~class
汎用~objの~streamを~~扱うときに共通的な`~queuing策$は、 単純に,[ 累積した`~chunk$の個数を,指定された`限界水位$に達するまで数え続ける ]ものである。 そのようなわけで、 この策も `out of the box^en で供される。 ◎ 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実装が,`下層~source$へ向けて`背圧$通達の送信を開始するまで ]に, (種類は問わず) 10 個の`~chunk$を,可読~streamの`下層~source$に~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 }) );
この事例では、[ `下層~sink$への以前の書込nが完遂するまで待機している間, 可書~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.
7.3.1. ~interface定義
`CountQueuingStrategy$I ~class用の~Web~IDL定義は: ◎ The Web IDL definition for the CountQueuingStrategy class is given as follows:
[`Exposed$=*] interface `CountQueuingStrategy@I { `CountQueuingStrategy$mc(`QueuingStrategyInit$I %init); readonly attribute `unrestricted double$ `highWaterMark$cqs; readonly attribute `Function$I `size$cqs; };
7.3.2. 内部~slot
`CountQueuingStrategy$I の各~instanceには, `highWaterMark@cQS 内部~slotがあり、 構築子に与えられた値を格納する。 ◎ Instances of CountQueuingStrategy have a [[highWaterMark]] internal slot, storing the value given in the constructor.
加えて,どの`大域~obj$ %大域~obj にも `~count~queuing策~size関数@ が結付けられる。 その値は `Function$I であり、 次に従って初期化するモノトスル: ◎ Additionally, every global object globalObject has an associated count queuing strategy size function, which is a Function whose value must be initialized as follows:
- %手続き ~LET 次を走らす~algo ⇒ ~RET 1 ◎ Let steps be the following steps: • Return 1.
- %F ~LET ~NOABRUPT `CreateBuiltinFunction$Ax( %手続き, 0, `size^l, « », %大域~obj に`関連な~realm$ ) ◎ Let F be ! CreateBuiltinFunction(steps, 0, "size", « », globalObject’s relevant Realm).
- %大域~obj の`~count~queuing策~size関数$ ~SET %F への参照を表現する `Function$I — その`~callback文脈$は、 %大域~obj に`関連な設定群~obj$になるとする ◎ Set globalObject’s count queuing strategy size function to a Function that represents a reference to F, with callback context equal to globalObject’s relevant settings object.
注記: この設計は、 いくぶん歴史的である。 その動機は、 `size$cqs は関数であって~methodではない — すなわち,その `this^jv 値を検査しない — ことを確保するよう欲されることにある。 更なる背景0は、 `課題 #1005@https://github.com/whatwg/streams/issues/1005$, `whatwg/webidl 課題 #819@https://github.com/whatwg/webidl/issues/819$ を見よ。 ◎ This design is somewhat historical. It is motivated by the desire to ensure that size is a function, not a method, i.e. it does not check its this value. See whatwg/streams#1005 and heycam/webidl#819 for more background.
7.3.3. 構築子, ~prop
- %strategy = `new CountQueuingStrategy$m({ `highWaterMark$qsi })
- 供された`限界水位$を伴う新たな `CountQueuingStrategy$I を作成する。 ◎ Creates a new CountQueuingStrategy with the provided high water mark.
- 供された`限界水位$は、 事前に検証されないことに注意。 それが[ ~numberでない/ `NaN^jv または負な~numberである ]場合、 結果の `CountQueuingStrategy$I は, 対応する~stream構築子にて例外を投出させることになる。 ◎ Note that the provided high water mark will not be validated ahead of time. Instead, if it is negative, NaN, or not a number, the resulting CountQueuingStrategy will cause the corresponding stream constructor to throw.
- %highWaterMark = %strategy.`highWaterMark$cqs
- 構築子に供された`限界水位$を返す。 ◎ Returns the high water mark provided to the constructor.
- %strategy.`size(chunk)$cqs
- 常に 1 を返すことにより, %chunk の~sizeを測定する。 これは、 合計~queue~sizeは~queue内にある`~chunk$の個数になることを確保する。 ◎ Measures the size of chunk by always returning 1. This ensures that the total queue size is a count of the number of chunks in the queue.
`new CountQueuingStrategy(init)@m 構築子~手続きは: ◎ The new CountQueuingStrategy(init) constructor steps are:
- コレ.`highWaterMark$cQS ~SET %init[ "`highWaterMark$qsi" ] ◎ Set this.[[highWaterMark]] to init["highWaterMark"].
`highWaterMark@cqs 取得子~手続きは: ◎ The highWaterMark getter steps are:
- ~RET コレ.`highWaterMark$cQS ◎ Return this.[[highWaterMark]].
`size@cqs 取得子~手続きは: ◎ The size getter steps are:
- ~RET コレに`関連な大域~obj$の`~count~queuing策~size関数$ ◎ Return this's relevant global object's count queuing strategy size function.
7.4. 抽象-演算
以下に与える~algoは、 ~stream構築子により利用され, `QueuingStrategy$I 辞書から関連な情報片を抽出する。 ◎ The following algorithms are used by the stream constructors to extract the relevant pieces from a QueuingStrategy dictionary.
`ExtractHighWaterMark(strategy, defaultHWM)@A は、次の手続きを遂行する: ◎ ExtractHighWaterMark(strategy, defaultHWM) performs the following steps:
- ~IF[ %strategy[ "`highWaterMark$qs" ] ~EQ ε ] ⇒ ~RET %defaultHWM ◎ If strategy["highWaterMark"] does not exist, return defaultHWM.
- %highWaterMark ~LET %strategy[ "`highWaterMark$qs" ] ◎ Let highWaterMark be strategy["highWaterMark"].
- ~IF[ %highWaterMark ~EQ `NaN^jv ]~OR[ %highWaterMark ~LT 0 ] ⇒ ~THROW `RangeError$E ◎ If highWaterMark is NaN or highWaterMark < 0, throw a RangeError exception.
- ~RET %highWaterMark ◎ Return highWaterMark.
注記: `+∞^jv は、 妥当な`限界水位$として明示的に許容され, `背圧$は決して適用されないようにする。 ◎ +∞ is explicitly allowed as a valid high water mark. It causes backpressure to never be applied.
`ExtractSizeAlgorithm(strategy)@A は、次の手続きを遂行する: ◎ ExtractSizeAlgorithm(strategy) performs the following steps:
- ~IF[ %strategy[ "`size$qs" ] ~EQ ε ] ⇒ ~RET 次を走らす~algo ⇒ ~RET 1 ◎ If strategy["size"] does not exist, return an algorithm that returns 1.
-
~RET 所与の ( %chunk ) に対し,次を走らす~algo ⇒ ~RET `~callback関数を呼出す$( %strategy[ "`size$qs" ], « %chunk »【, `投出し直す^i 】 ) ◎ Return an algorithm that performs the following steps, taking a chunk argument: • Return the result of invoking strategy["size"] with argument list « chunk ».
8. ~support用の抽象-演算
以下に与える各~抽象-演算は、 複数の型の~streamの実装を~supportするので,主要な節の下に置かれていない。 ◎ The following abstract operations each support the implementation of more than one type of stream, and as such are not grouped under the major sections above.
8.1. 個別~size付き~queue
この仕様における各種~streamは、 “個別~size付き~queue” ( `queue-with-sizes^en )と称される~data構造を利用して,~queueしておかれた値を, それに決定された~sizeと伴に格納する。 個別~size付き~queueは、 仕様~levelの様々な~objに包含され,常に[ `queue^sl, `queueTotalSize^sl と命名され,~pairにされる 2 つの内部~slot ]を有する~objとして表現される。 `queue^sl は,`~sizeを伴う値$たちが成す`~list$であり、 `queueTotalSize^sl は,~JS `Number$jt — すなわち,倍精度~浮動小数点~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 value-with-sizes, 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^sl ~slotに~~収まり続けるようにするが、 浮動小数点 算術の精度には限りがあるため, `queue^sl 内の すべての`~chunk$の~sizeを加算していくことに`等価ではない^em。 (しかしながら,この相違が生じるのは、 ~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.)
`~sizeを伴う値@ は、 次に挙げる`~item$sctからなる`構造体$である ⇒# `値@Vs, `~size@Vs ◎ In what follows, a value-with-size is a struct with the two items value and size.
`DequeueValue(container)@A は、次を遂行する: ◎ DequeueValue(container) performs the following steps:
- ~Assert: %container は `queue^sl, `queueTotalSize^sl 両~内部~slotを有する ◎ Assert: container has [[queue]] and [[queueTotalSize]] internal slots.
- ~Assert: %container.`queue^sl は`空$でない ◎ Assert: container.[[queue]] is not empty.
- %valueWithSize ~LET %container.`queue^sl[0] ◎ Let valueWithSize be container.[[queue]][0].
- %container.`queue^sl から %valueWithSize を`除去する$ ◎ Remove valueWithSize from container.[[queue]].
- %container.`queueTotalSize^sl ~SET %container.`queueTotalSize^sl ~MINUS %valueWithSize の`~size$Vs ◎ Set container.[[queueTotalSize]] to container.[[queueTotalSize]] − valueWithSize’s size.
- ~IF[ %container.`queueTotalSize^sl ~LT 0 (これは丸め誤差に因り生じ得る) ] ⇒ %container.`queueTotalSize^sl ~SET 0 ◎ If container.[[queueTotalSize]] < 0, set container.[[queueTotalSize]] to 0. (This can occur due to rounding errors.)
- ~RET %valueWithSize の`値$Vs ◎ Return valueWithSize’s value.
`EnqueueValueWithSize(container, value, size)@A は、次を遂行する: ◎ EnqueueValueWithSize(container, value, size) performs the following steps:
- ~Assert: %container は `queue^sl, `queueTotalSize^sl 両~内部~slotを有する ◎ Assert: container has [[queue]] and [[queueTotalSize]] internal slots.
- ~IF[ ~NOABRUPT `IsNonNegativeNumber$A( %size ) ~EQ ~F ] ⇒ ~THROW `RangeError$E ◎ If ! IsNonNegativeNumber(size) is false, throw a RangeError exception.
- ~IF[ %size ~EQ `+∞^jv ] ⇒ ~THROW `RangeError$E ◎ If size is +∞, throw a RangeError exception.
- %container.`queue^sl に[ 次を伴う,新たな`~sizeを伴う値$ ]を`付加する$ ⇒# `値$Vs ~SET %value, `~size$Vs ~SET %size ◎ Append a new value-with-size with value value and size size to container.[[queue]].
- %container.`queueTotalSize^sl ~INCBY %size ◎ Set container.[[queueTotalSize]] to container.[[queueTotalSize]] + size.
`PeekQueueValue(container)@A は、次を遂行する: ◎ PeekQueueValue(container) performs the following steps:
- ~Assert: %container は `queue^sl, `queueTotalSize^sl 両~内部~slotを有する ◎ Assert: container has [[queue]] and [[queueTotalSize]] internal slots.
- ~Assert: %container.`queue^sl は`空$でない ◎ Assert: container.[[queue]] is not empty.
- %valueWithSize ~LET %container.`queue^sl[0] ◎ Let valueWithSize be container.[[queue]][0].
- ~RET %valueWithSize の`値$Vs ◎ Return valueWithSize’s value.
`ResetQueue(container)@A は、次を遂行する: ◎ ResetQueue(container) performs the following steps:
- ~Assert: %container は `queue^sl, `queueTotalSize^sl 両~内部~slotを有する ◎ Assert: container has [[queue]] and [[queueTotalSize]] internal slots.
- %container.`queue^sl ~SET 新たな空`~list$ ◎ Set container.[[queue]] to a new empty list.
- %container.`queueTotalSize^sl ~SET 0 ◎ Set container.[[queueTotalSize]] to 0.
8.2. 転送-可能な~stream
転送-可能な~streamは、[ `可書~側$, `可読~側$ ]が異なる`~realm$に属するような,特別な種類の恒等変換を利用して実装される。 以下に与える抽象-演算は、 このような “~realmをまたがる形式変換” を実装するために利用される。 ◎ Transferable streams are implemented using a special kind of identity transform which has the writable side in one realm and the readable side in another realm. The following abstract operations are used to implement these "cross-realm transforms".
`CrossRealmTransformSendError(port, error)@A は、次の手続きを遂行する: ◎ CrossRealmTransformSendError(port, error) performs the following steps:
-
`PackAndPostMessage$A( %port, `error^l, %error ) ◎ Perform PackAndPostMessage(port, "error", error),\
注記: 結果は、 単に破棄される。 この抽象-演算が遂行されるときには,すでに~errorした状態にあり、 更なる~errorは取扱えないので。 ◎ discarding the result. ◎ As we are already in an errored state when this abstract operation is performed, we cannot handle further errors, so we just discard them.
`PackAndPostMessage(port, type, value)@A は、次の手続きを遂行する: ◎ PackAndPostMessage(port, type, value) performs the following steps:
- %message ~LET `OrdinaryObjectCreate$Ax( ~NULL ) ◎ Let message be OrdinaryObjectCreate(null).
- ~NOABRUPT `CreateDataProperty$Ax( %message, `type^l, %type ) ◎ Perform ! CreateDataProperty(message, "type", type).
- ~NOABRUPT `CreateDataProperty$Ax( %message, `value^l, %value ) ◎ Perform ! CreateDataProperty(message, "value", value).
- %targetPort ~LET %port に連絡された~portは[ 在るならば それ/ 無いならば ~NULL ] ◎ Let targetPort be the port with which port is entangled, if any; otherwise let it be null.
- %options ~LET «[ `transfer^l → « » ]» ◎ Let options be «[ "transfer" → « » ]».
- `~message~portに~messageを投函する手続き$(【%port,】 %targetPort, %message, %options ) ◎ Run the message port post message steps providing targetPort, message, and options.
注記: `~message~portに~messageを投函する手続き$を重複せずに済ますため、 ~JS~objが転送~用に利用される。 `Object.prototype$jI からの干渉を避けるため、 ~objの~prototypeは ~NULL に設定される。 ◎ A JavaScript object is used for transfer to avoid having to duplicate the message port post message steps. The prototype of the object is set to null to avoid interference from %Object.prototype%.
`PackAndPostMessageHandlingError(port, type, value)@A は、次の手続きを遂行する: ◎ PackAndPostMessageHandlingError(port, type, value) performs the following steps:
- %result ~LET `PackAndPostMessage$A( %port, %type, %value ) ◎ Let result be PackAndPostMessage(port, type, value).
- ~IF[ %result は`中途完了^である ] ⇒ ~NOABRUPT `CrossRealmTransformSendError$A( %port, %result .`Value^sl ) ◎ If result is an abrupt completion, • Perform ! CrossRealmTransformSendError(port, result.[[Value]]).
- ~RET %result — `完了~record$として返す ◎ Return result as a completion record.
`SetUpCrossRealmTransformReadable(stream, port)@A は、次の手続きを遂行する: ◎ SetUpCrossRealmTransformReadable(stream, port) performs the following steps:
- ~NOABRUPT `InitializeReadableStream$A( %stream ) ◎ Perform ! InitializeReadableStream(stream).
- %controller ~LET `新たな$ `ReadableStreamDefaultController$I ◎ Let controller be a new ReadableStreamDefaultController.
-
%port の `message$et ~event用に[ 次の手続きを伴う~handler ]を追加する: ◎ Add a handler for port’s message event with the following steps:
- %data ~LET 当の~messageを成す~data ◎ Let data be the data of the message.
- ~Assert: %data は `Object$jt である ◎ Assert: data is an Object.
- %type ~LET ~NOABRUPT `Get$Ax( %data, `type^l ) ◎ Let type be ! Get(data, "type").
- %value ~LET ~NOABRUPT `Get$Ax( %data, `value^l ) ◎ Let value be ! Get(data, "value").
- ~Assert: %type は `String$jt である ◎ Assert: type is a String.
- ~IF[ %type ~EQ `chunk^l, ] ⇒ ~NOABRUPT `ReadableStreamDefaultControllerEnqueue$A( %controller, %value ) ◎ If type is "chunk", • Perform ! ReadableStreamDefaultControllerEnqueue(controller, value).
-
~ELIF[ %type ~EQ `close^l ]: ◎ Otherwise, if type is "close",
- ~NOABRUPT `ReadableStreamDefaultControllerClose$A( %controller ) ◎ Perform ! ReadableStreamDefaultControllerClose(controller).
- %port の連絡を断つ ◎ Disentangle port.
-
~ELIF[ %type ~EQ `error^l, ]: ◎ Otherwise, if type is "error",
- ~NOABRUPT `ReadableStreamDefaultControllerError$A( %controller, %value ) ◎ Perform ! ReadableStreamDefaultControllerError(controller, value).
- %port の連絡を断つ ◎ Disentangle port.
-
%port の `messageerror$et ~event用に[ 次の手続きを伴う~handler ]を追加する: ◎ Add a handler for port’s messageerror event with the following steps:
- %error ~LET 新たな `DataCloneError$E 例外 ◎ Let error be a new "DataCloneError" DOMException.
- ~NOABRUPT `CrossRealmTransformSendError$A( %port, %error ) ◎ Perform ! CrossRealmTransformSendError(port, error).
- ~NOABRUPT `ReadableStreamDefaultControllerError$A( %controller, %error ) ◎ Perform ! ReadableStreamDefaultControllerError(controller, error).
- %port の連絡を断つ ◎ Disentangle port.
- %port の `~port~message~queue$を可能化する ◎ Enable port’s port message queue.
- %startAlgorithm ~LET 次を走らす~algo ⇒ ~RET `undefined^jv ◎ Let startAlgorithm be an algorithm that returns undefined.
-
%pullAlgorithm ~LET 次を走らす~algo: ◎ Let pullAlgorithm be the following steps:
- ~NOABRUPT `PackAndPostMessage$A( %port, `pull^l, `undefined^jv ) ◎ Perform ! PackAndPostMessage(port, "pull", undefined).
- ~RET `解決される~promise$( `undefined^jv ) ◎ Return a promise resolved with undefined.
-
%cancelAlgorithm ~LET 所与の ( %reason ) に対し,次を走らす~algo: ◎ Let cancelAlgorithm be the following steps, taking a reason argument:
- %result ~LET `PackAndPostMessageHandlingError$A( %port, `error^l, %reason ) ◎ Let result be PackAndPostMessageHandlingError(port, "error", reason).
- %port の連絡を断つ ◎ Disentangle port.
- ~IF[ %result は`中途完了^である ] ⇒ ~RET `却下される~promise$( %result.`Value^sl ) ◎ If result is an abrupt completion, return a promise rejected with result.[[Value]].
- ~ELSE ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ Otherwise, return a promise resolved with undefined.
- %sizeAlgorithm ~LET 次を走らす~algo ⇒ ~RET 1 ◎ Let sizeAlgorithm be an algorithm that returns 1.
- ~NOABRUPT `SetUpReadableStreamDefaultController$A( ↓ ) ⇒# %stream, %controller, %startAlgorithm, %pullAlgorithm, %cancelAlgorithm, 0, %sizeAlgorithm ◎ Perform ! SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, 0, sizeAlgorithm).
注記: 実装には、 この~algo内の ~Assert における失敗を明示的に取扱うことが奨励される — 入力は信用されない文脈から来るかもしれず、 見逃すと~securityの課題へ至りかねないので。 ◎ Implementations are encouraged to explicitly handle failures from the asserts in this algorithm, as the input might come from an untrusted context. Failure to do so could lead to security issues.
`SetUpCrossRealmTransformWritable(stream, port)@A は、次の手続きを遂行する: ◎ SetUpCrossRealmTransformWritable(stream, port) performs the following steps:
- ~NOABRUPT `InitializeWritableStream$A( %stream ) ◎ Perform ! InitializeWritableStream(stream).
- %controller ~LET `新たな$ `WritableStreamDefaultController$I ◎ Let controller be a new WritableStreamDefaultController.
- %backpressurePromise ~LET `新たな~promise$ ◎ Let backpressurePromise be a new promise.
-
%port の `message$et ~event用に[ 次の手続きを伴う~handler ]を追加する: ◎ Add a handler for port’s message event with the following steps:
- %data ~LET 当の~messageを成す~data ◎ Let data be the data of the message.
- ~Assert: %data は `Object$jt である ◎ Assert: data is an Object.
- %type ~LET ~NOABRUPT `Get$Ax( %data, `type^l ) ◎ Let type be ! Get(data, "type").
- %value ~LET ~NOABRUPT `Get$Ax( %data, `value^l ) ◎ Let value be ! Get(data, "value").
- ~Assert: %type は `String$jt である ◎ Assert: type is a String.
-
~IF[ %type ~EQ `pull^l ]: ◎ If type is "pull",
-
~IF[ %backpressurePromise ~NEQ `undefined^jv ]: ◎ If backpressurePromise is not undefined,
- `~promiseを解決する$( %backpressurePromise, `undefined^jv ) ◎ Resolve backpressurePromise with undefined.
- %backpressurePromise ~SET `undefined^jv ◎ Set backpressurePromise to undefined.
-
-
~ELIF[ %type ~EQ `error^l ]: ◎ Otherwise, if type is "error",
- ~NOABRUPT `WritableStreamDefaultControllerErrorIfNeeded$A( %controller, %value ) ◎ Perform ! WritableStreamDefaultControllerErrorIfNeeded(controller, value).
-
~IF[ %backpressurePromise ~NEQ `undefined^jv ]: ◎ If backpressurePromise is not undefined,
- `~promiseを解決する$( %backpressurePromise, `undefined^jv ) ◎ Resolve backpressurePromise with undefined.
- %backpressurePromise ~SET `undefined^jv ◎ Set backpressurePromise to undefined.
-
%port の `messageerror$et ~event用に[ 次の手続きを伴う~handler ]を追加する: ◎ Add a handler for port’s messageerror event with the following steps:
- %error ~LET 新たな `DataCloneError$E 例外 ◎ Let error be a new "DataCloneError" DOMException.
- ~NOABRUPT `CrossRealmTransformSendError$A( %port, %error ) ◎ Perform ! CrossRealmTransformSendError(port, error).
- ~NOABRUPT `WritableStreamDefaultControllerErrorIfNeeded$A( %controller, %error ) ◎ Perform ! WritableStreamDefaultControllerErrorIfNeeded(controller, error).
- %port の連絡を断つ ◎ Disentangle port.
- %port の`~port~message~queue$を可能化する ◎ Enable port’s port message queue.
- %startAlgorithm ~LET 次を走らす~algo ⇒ ~RET `undefined^jv ◎ Let startAlgorithm be an algorithm that returns undefined.
-
%writeAlgorithm ~LET 所与の ( %chunk ) に対し,次を走らす~algo: ◎ Let writeAlgorithm be the following steps, taking a chunk argument:
- ~IF[ %backpressurePromise ~EQ `undefined^jv ] ⇒ %backpressurePromise ~SET `解決される~promise$( `undefined^jv ) ◎ If backpressurePromise is undefined, set backpressurePromise to a promise resolved with undefined.
-
~RET `~promiseに反応する$( %backpressurePromise ) — 次を与える下で: ◎ Return the result of reacting to backpressurePromise with\
-
`充足~手続き^i は: ◎ the following fulfillment steps:
- %backpressurePromise ~SET `新たな~promise$ ◎ Set backpressurePromise to a new promise.
- %result ~LET `PackAndPostMessageHandlingError$A( %port, `chunk^l, %chunk ) ◎ Let result be PackAndPostMessageHandlingError(port, "chunk", chunk).
-
~IF[ %result は`中途完了^である ]: ◎ If result is an abrupt completion,
- %port の連絡を断つ ◎ Disentangle port.
- ~RET `却下される~promise$( %result.`Value^sl ) ◎ Return a promise rejected with result.[[Value]].
- ~ELSE ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ Otherwise, return a promise resolved with undefined.
-
-
%closeAlgorithm ~LET 次を走らす~algo: ◎ Let closeAlgorithm be the folowing steps:
- ~NOABRUPT `PackAndPostMessage$A( %port, `close^l, `undefined^jv ) ◎ Perform ! PackAndPostMessage(port, "close", undefined).
- %port の連絡を断つ ◎ Disentangle port.
- ~RET `解決される~promise$( `undefined^jv ) ◎ Return a promise resolved with undefined.
-
%abortAlgorithm ~LET 所与の ( %reason ) に対し,次を走らす手続き: ◎ Let abortAlgorithm be the following steps, taking a reason argument:
- %result ~LET `PackAndPostMessageHandlingError$A( %port, `error^l, %reason ) ◎ Let result be PackAndPostMessageHandlingError(port, "error", reason).
- %port の連絡を断つ ◎ Disentangle port.
- ~IF[ %result は`中途完了^である ] ⇒ ~RET `却下される~promise$( %result.`Value^sl ) ◎ If result is an abrupt completion, return a promise rejected with result.[[Value]].
- ~ELSE ⇒ ~RET `解決される~promise$( `undefined^jv ) ◎ Otherwise, return a promise resolved with undefined.
- %sizeAlgorithm ~LET 次を走らす~algo ⇒ ~RET 1 ◎ Let sizeAlgorithm be an algorithm that returns 1.
- ~NOABRUPT `SetUpWritableStreamDefaultController$A( ↓ ) ⇒# %stream, %controller, %startAlgorithm, %writeAlgorithm, %closeAlgorithm, %abortAlgorithm, 1, %sizeAlgorithm ◎ Perform ! SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, 1, sizeAlgorithm).
注記: 実装には、 この~algo内の ~Assert における失敗を明示的に取扱うことが奨励される — 入力は信用されない文脈から来るかもしれず、 見逃すと~securityの課題へ至りかねないので。 ◎ Implementations are encouraged to explicitly handle failures from the asserts in this algorithm, as the input might come from an untrusted context. Failure to do so could lead to security issues.
8.3. 諸々の演算
以下に与える抽象-演算は、 ~~便利用の寄せ集めである。 ◎ The following abstract operations are a grab-bag of utilities.
`CanTransferArrayBuffer(O)@A は、次の手続きを遂行する: ◎ CanTransferArrayBuffer(O) performs the following steps:
- ~Assert: %O は `Object$jt である ◎ Assert: O is an Object.
- ~Assert: %O は `ArrayBufferData^sl 内部~slotを有する ◎ Assert: O has an [[ArrayBufferData]] internal slot.
- ~IF[ ~NOABRUPT `IsDetachedBuffer$Ax( %O ) ~EQ ~T ] ⇒ ~RET ~F ◎ If ! IsDetachedBuffer(O) is true, return false.
- ~IF[ `SameValue$Ax( %O.`ArrayBufferDetachKey^sl, `undefined^jv ) ~EQ ~F ] ⇒ ~RET ~F ◎ If SameValue(O.[[ArrayBufferDetachKey]], undefined) is false, return false.
- ~RET ~T ◎ Return true.
`IsNonNegativeNumber(v)@A は、次を遂行する: ◎ IsNonNegativeNumber(v) performs the following steps:
- ~IF[ %v は `Number$jt でない ] ⇒ ~RET ~F ◎ If v is not a Number, return false.
- ~IF[ %v ~EQ `NaN^jv ] ⇒ ~RET ~F ◎ If v is NaN, return false.
- ~IF[ %v ~LT 0 ] ⇒ ~RET ~F ◎ If v < 0, return false.
- ~RET ~T ◎ Return true.
`TransferArrayBuffer(O)@A は、次を遂行する: ◎ TransferArrayBuffer(O) performs the following steps:
- ~Assert: ~NOABRUPT `IsDetachedBuffer$Ax( %O ) ~EQ ~F ◎ Assert: ! IsDetachedBuffer(O) is false.
- %arrayBufferData ~LET %O.`ArrayBufferData^sl ◎ Let arrayBufferData be O.[[ArrayBufferData]].
- %arrayBufferByteLength ~LET %O.`ArrayBufferByteLength^sl ◎ Let arrayBufferByteLength be O.[[ArrayBufferByteLength]].
-
~ABRUPT `DetachArrayBuffer$Ax( %O ) ◎ Perform ? DetachArrayBuffer(O).
注記: これは、[ %O は `ArrayBufferDetachKey^sl を有していて, `undefined^jv でない場合 ]には,例外を投出することになる — `WebAssembly.Memory$c の `buffer$c `WASM-JS-API-1$r など。 ◎ This will throw an exception if O has an [[ArrayBufferDetachKey]] that is not undefined, such as a WebAssembly.Memory's buffer. [WASM-JS-API-1]
- ~RET 新たな `ArrayBuffer$I ~obj — `現在の~realm$内に作成され, 次のように設定された ⇒# `ArrayBufferData^sl 内部~slot ~SET %arrayBufferData, `ArrayBufferByteLength^sl 内部~slot ~SET %arrayBufferByteLength ◎ Return a new ArrayBuffer object, created in the current Realm, whose [[ArrayBufferData]] internal slot value is arrayBufferData and whose [[ArrayBufferByteLength]] internal slot value is arrayBufferByteLength.
`CloneAsUint8Array(O)@A は、次の手続きを遂行する: ◎ CloneAsUint8Array(O) performs the following steps:
- ~Assert: %O は `Object$jt である ◎ Assert: O is an Object.
- ~Assert: %O は `ViewedArrayBuffer^sl 内部~slotを有する ◎ Assert: O has an [[ViewedArrayBuffer]] internal slot.
- ~Assert: ~NOABRUPT `IsDetachedBuffer$Ax( %O.`ViewedArrayBuffer^sl ) ~EQ ~F ◎ Assert: ! IsDetachedBuffer(O.[[ViewedArrayBuffer]]) is false.
- %buffer ~LET ~ABRUPT `CloneArrayBuffer$Ax( %O.`ViewedArrayBuffer^sl, %O.`ByteOffset^sl, %O.`ByteLength^sl, `ArrayBuffer$jI ) ◎ Let buffer be ? CloneArrayBuffer(O.[[ViewedArrayBuffer]], O.[[ByteOffset]], O.[[ByteLength]], %ArrayBuffer%).
- %array ~LET ~NOABRUPT `Construct$Ax( `有型~配列$, « %buffer » ) ◎ Let array be ! Construct(%Uint8Array%, « buffer »).
- ~RET %array ◎ Return array.
`StructuredClone(v)@A は、次の手続きを遂行する: ◎ StructuredClone(v) performs the following steps:
- %serialized ~LET ~ABRUPT `StructuredSerialize$A( %v ) ◎ Let serialized be ? StructuredSerialize(v).
- ~RET ~ABRUPT `StructuredDeserialize$A( %serialized, `現在の~realm$ ) ◎ Return ? StructuredDeserialize(serialized, the current Realm).
9. 他の仕様における~streamの利用-法
この標準のかなりの部分は、 ~streamの内部的な機構に割かれている。 他の仕様は、 一般に,これらの詳細~について構う必要はない。 代わりに,他の仕様は、 この標準が定義する様々な~IDL型を介して,以下に挙げる定義に沿って, この標準と~interfaceするベキである。 ◎ Much of this standard concerns itself with the internal machinery of streams. Other specifications generally do not need to worry about these details. Instead, they should interface with this standard via the various IDL types it defines, along with the following definitions.
他の仕様は、 この標準にて定義される様々な内部~slotを直に[ 検分する/操作する ]ベキでない。 類似に,他の仕様は、 この標準にて定義される抽象-演算を利用するベキでない。 そのような直な用法は、 この標準が保守する不変則を破るものになり得る。 ◎ Specifications should not directly inspect or manipulate the various internal slots defined in this standard. Similarly, they should not use the abstract operations defined here. Such direct usage can break invariants that this standard otherwise maintains.
注記: 他の仕様の策定者は、 ここで~supportされない仕方で~streamと~interfaceするよう求めるときは, `課題を申請する@https://github.com/whatwg/streams/issues/new$こと。 この節は、 必要に応じて,組織的に成長するものと意図されている。 ◎ If your specification wants to interface with streams in a way not supported here, file an issue. This section is intended to grow organically as needed.
9.1. 可読~stream
9.1.1. 作成と操作
`ReadableStream$I ~obj %~stream を `設定しておく@RS ときは、 所与の:
- %~pull~algo
- ε /~algo (省略時は ε )
- ~algoは、 ~promiseを返してもヨイ。
- %取消~algo
- ε / ~algo (省略時は ε )
- ~algoは、 ~promiseを返してもヨイ。
- %限界水位
- 負でも `NaN^jv でもない~number (省略時は 1 )
- %~size~algo
- ε / ~algo (省略時は ε )
- ~algoは、 `~chunk$~objを受容して~numberを返すとする。
に対し,次の手続きを遂行する:
◎ To set up a newly-created-via-Web IDL ReadableStream object stream, given\ an optional algorithm pullAlgorithm,\ an optional algorithm cancelAlgorithm,\ an optional number highWaterMark (default 1),\ and an optional algorithm sizeAlgorithm,\ perform the following steps.\ If given,\ pullAlgorithm and cancelAlgorithm may return a promise.\ If given, sizeAlgorithm must be an algorithm accepting chunk objects and returning a number;\ and if given, highWaterMark must be a non-negative, non-NaN number.- ~Assert: %~stream は`~Web~IDLを介して新たに作成した$ものである。 ◎ ↑
- %開始~algo ~LET 次を走らす~algo ⇒ ~RET `undefined^jv ◎ Let startAlgorithm be an algorithm that returns undefined.
-
%~pull~algo包装体 ~LET 次を走らす~algo: ◎ Let pullAlgorithmWrapper be an algorithm that runs these steps:
- %結果 ~LET ~NULL ◎ ↓
- ~IF[ %~pull~algo ~NEQ ε ] ⇒ %結果 ~SET %~pull~algo() ⇒ 例外 %e が投出されたときは ⇒ ~RET `却下される~promise$( %e ) ◎ Let result be the result of running pullAlgorithm, if pullAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
- ~RET %結果 に応じて ⇒# `Promise$I であるならば %結果 / ~ELSE_ `解決される~promise$( `undefined^jv ) ◎ If result is a Promise, then return result. ◎ Return a promise resolved with undefined.
-
%取消~algo包装体 ~LET 次を走らす~algo: ◎ Let cancelAlgorithmWrapper be an algorithm that runs these steps:
- %結果 ~LET ~NULL ◎ ↓
- ~IF[ %取消~algo ~NEQ ε ] ⇒ %結果 ~SET %取消~algo() ⇒ 例外 %e が投出されたときは ⇒ ~RET `却下される~promise$( %e ) ◎ Let result be the result of running cancelAlgorithm, if cancelAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
- ~RET %結果 に応じて ⇒# `Promise$I であるならば %結果 / ~ELSE_ `解決される~promise$( `undefined^jv ) ◎ If result is a Promise, then return result. ◎ Return a promise resolved with undefined.
- ~IF[ %~size~algo ~EQ ε ] ⇒ %~size~algo ~SET 次を走らす~algo ⇒ ~RET 1 ◎ If sizeAlgorithm was not given, then set it to an algorithm that returns 1.
- ~NOABRUPT `InitializeReadableStream$A( %~stream ) ◎ Perform ! InitializeReadableStream(stream).
- %制御器 ~LET `新たな$ `ReadableStreamDefaultController$I ◎ Let controller be a new ReadableStreamDefaultController.
- ~NOABRUPT `SetUpReadableStreamDefaultController$A( ↓ ) ⇒# %~stream, %制御器, %開始~algo, %~pull~algo包装体, %取消~algo包装体, %限界水位, %~size~algo ◎ Perform ! SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithmWrapper, cancelAlgorithmWrapper, highWaterMark, sizeAlgorithm).
`ReadableStream$I ~obj %~stream を `~byte読取り~support付きで設定しておく@RS ときは、 所与の:
- %~pull~algo
- ε / ~algo (省略時は ε )
- ~algoは、 ~promiseを返してもヨイ。
- %取消~algo
- ε / ~algo (省略時は ε )
- ~algoは、 ~promiseを返してもヨイ。
- %限界水位
- 負でも `NaN^jv でもない ~number (省略時は 0 )
に対し,次の手続きを遂行する:
◎ To set up with byte reading support a newly-created-via-Web IDL ReadableStream object stream, given\ an optional algorithm pullAlgorithm,\ an optional algorithm cancelAlgorithm,\ and an optional number highWaterMark (default 0),\ perform the following steps.\ If given, pullAlgorithm and cancelAlgorithm may return a promise.\ If given, highWaterMark must be a non-negative, non-NaN number.- ~Assert: %~stream は`~Web~IDLを介して新たに作成した$ものである。 ◎ ↑
- %開始~algo ~LET 次を走らす~algo ⇒ ~RET `undefined^jv ◎ Let startAlgorithm be an algorithm that returns undefined.
-
%~pull~algo包装体 ~LET 次を走らす~algo: ◎ Let pullAlgorithmWrapper be an algorithm that runs these steps:
- %結果 ~LET ~NULL ◎ ↓
- ~IF[ %~pull~algo ~NEQ ε ] ⇒ %結果 ~SET %~pull~algo() ⇒ 例外 %e が投出されたときは ⇒ ~RET `却下される~promise$( %e ) ◎ Let result be the result of running pullAlgorithm, if pullAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
- ~RET %結果 に応じて ⇒# `Promise$I であるならば %結果 / ~ELSE_ `解決される~promise$( `undefined^jv ) ◎ If result is a Promise, then return result. ◎ Return a promise resolved with undefined.
-
%取消~algo包装体 ~LET 所与の ( %事由 ) に対し, 次を走らす~algo: ◎ Let cancelAlgorithmWrapper be an algorithm that runs these steps given reason:
- %結果 ~LET ~NULL ◎ ↓
- ~IF[ %取消~algo ~NEQ ε ] ⇒ %結果 ~SET %取消~algo( %事由 ) ⇒ 例外 %e が投出されたときは ⇒ ~RET `却下される~promise$( %e ) ◎ Let result be the result of running cancelAlgorithm given reason, if cancelAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
- ~RET %結果 に応じて ⇒# `Promise$I であるならば %結果 / ~ELSE_ `解決される~promise$( `undefined^jv ) ◎ If result is a Promise, then return result. ◎ Return a promise resolved with undefined.
- ~NOABRUPT `InitializeReadableStream$A( %~stream ) ◎ Perform ! InitializeReadableStream(stream).
- %制御器 ~LET `新たな$ `ReadableByteStreamController$I ◎ Let controller be a new ReadableByteStreamController.
- ~NOABRUPT `SetUpReadableByteStreamController$A( ↓ ) ⇒# %~stream, %制御器, %開始~algo, %~pull~algo包装体, %取消~algo包装体, %限界水位, `undefined^jv ◎ Perform ! SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithmWrapper, cancelAlgorithmWrapper, highWaterMark, undefined).
したがって,他の仕様から `ReadableStream$I を作成するときは、 次の様な 2 段からなる処理nになる: ◎ Creating a ReadableStream from other specifications is thus a two-step process, like so:
- %可読~stream ~LET `新たな$ `ReadableStream$I ◎ Let readableStream be a new ReadableStream.
- %可読~stream を`設定しておく$RS … ◎ Set up readableStream given….
注記: `ReadableStream$I の下位classは、 その構築子~手続きの内側にて,コレを[ `設定しておく$RS/ `~byte読取り~support付きで設定しておく$RS ]演算を直に利用することになる。 ◎ Subclasses of ReadableStream will use the set up or set up with byte reading support operations directly on the this value inside their constructor steps.
以下に与える~algoは、 上の[ `設定しておく$RS/ `~byte読取り~support付きで設定しておく$RS ]~algoを介して初期化されたもの以外の `ReadableStream$I ~instance (例:~web開発者が作成した~instance)には,利用してはナラナイ。 ◎ The following algorithms must only be used on ReadableStream instances initialized via the above set up or set up with byte reading support algorithms (not, e.g., on web-developer-created instances):
`ReadableStream$I %~stream の `限界水位までの~queueの残り~size@RS ( `desired size to fill up to the high water mark^en ) は、次の手続きを走らせた結果になる: ◎ A ReadableStream stream’s desired size to fill up to the high water mark is the result of running the following steps:
- ~IF[ %~stream は`読取n可能$RSでない ] ⇒ ~RET 0 ◎ If stream is not readable, then return 0.
- ~IF[ %~stream.`controller$rS は `ReadableByteStreamController$I を`実装する$ ] ⇒ ~RET ~NOABRUPT `ReadableByteStreamControllerGetDesiredSize$A( %~stream.`controller$rS ) ◎ If stream.[[controller]] implements ReadableByteStreamController, then return ! ReadableByteStreamControllerGetDesiredSize(stream.[[controller]]).
- ~RET ~NOABRUPT `ReadableStreamDefaultControllerGetDesiredSize$A( %~stream.`controller$rS ) ◎ Return ! ReadableStreamDefaultControllerGetDesiredSize(stream.[[controller]]).
`ReadableStream$I %~stream は、 次を満たすならば `もっと~dataが必要@RS ( `needs more data^en )とされる ⇒ %~stream の`限界水位までの~queueの残り~size$RS ~GT 0 ◎ A ReadableStream needs more data if its desired size to fill up to the high water mark is greater than zero.
`ReadableStream$I %~stream を `~closeする@RS ときは: ◎ To close a ReadableStream stream:
-
~IF[ %~stream.`controller$rS は `ReadableByteStreamController$I を`実装する$ ]: ◎ If stream.[[controller]] implements ReadableByteStreamController,
- ~NOABRUPT `ReadableByteStreamControllerClose$A( %~stream.`controller$rS ) ◎ Perform ! ReadableByteStreamControllerClose(stream.[[controller]]).
- ~IF[ %~stream.`controller$rS.`pendingPullIntos$rbsC は`空$でない ] ⇒ ~NOABRUPT `ReadableByteStreamControllerRespond$A( %~stream.`controller$rS, 0 ) ◎ If stream.[[controller]].[[pendingPullIntos]] is not empty, perform ! ReadableByteStreamControllerRespond(stream.[[controller]], 0).
- ~ELSE ⇒ ~NOABRUPT `ReadableStreamDefaultControllerClose$A( %~stream.`controller$rS ) ◎ Otherwise, perform ! ReadableStreamDefaultControllerClose(stream.[[controller]]).
`ReadableStream$I %~stream を `~errorにする@RS ときは、 所与の ( ~JS値 %e ) に対し: ◎ To error a ReadableStream stream given a JavaScript value e:
- ~IF[ %~stream.`controller$rS は `ReadableByteStreamController$I を`実装する$ ] ⇒ ~NOABRUPT `ReadableByteStreamControllerError$A( %~stream.`controller$rS, %e ) ◎ If stream.[[controller]] implements ReadableByteStreamController, then perform ! ReadableByteStreamControllerError(stream.[[controller]], e).
- ~ELSE ⇒ ~NOABRUPT `ReadableStreamDefaultControllerError$A( %~stream.`controller$rS, %e ) ◎ Otherwise, perform ! ReadableStreamDefaultControllerError(stream.[[controller]], e).
`ReadableStream$I %~stream に `~chunkを~enqueueする@RS ときは、 所与の ( ~JS値 %~chunk ) に対し: ◎ To enqueue the JavaScript value chunk into a ReadableStream stream:
-
~IF[ %~stream.`controller$rS は `ReadableStreamDefaultController$I を`実装する$ ]: ◎ If stream.[[controller]] implements ReadableStreamDefaultController,
- ~NOABRUPT `ReadableStreamDefaultControllerEnqueue$A( %~stream.`controller$rS, %~chunk ) ◎ Perform ! ReadableStreamDefaultControllerEnqueue(stream.[[controller]], chunk).
-
~ELSE: ◎ Otherwise,
- ~Assert: %~stream.`controller$rS は `ReadableByteStreamController$I を`実装する$ ◎ Assert: stream.[[controller]] implements ReadableByteStreamController.
- ~Assert: %~chunk は `ArrayBufferView$I である ◎ Assert: chunk is an ArrayBufferView.
- %~BYOB~view ~LET %~stream 用の`現在の~BYOB要請~view$RS ◎ Let byobView be the current BYOB request view for stream.
-
~IF[ %~BYOB~view ~NEQ ~NULL ]~AND[ %~chunk.`ViewedArrayBuffer^sl ~EQ %~BYOB~view.`ViewedArrayBuffer^sl ]: ◎ If byobView is non-null, and chunk.[[ViewedArrayBuffer]] is byobView.[[ViewedArrayBuffer]], then:
- ~Assert: %~chunk.`ByteOffset^sl ~EQ %~BYOB~view.`ByteOffset^sl ◎ Assert: chunk.[[ByteOffset]] is byobView.[[ByteOffset]].
-
~Assert: %~chunk.`ByteLength^sl ~LTE %~BYOB~view.`ByteLength^sl ◎ Assert: chunk.[[ByteLength]] ≤ byobView.[[ByteLength]].
注記: これらの ~Assert は、 次を確保する ⇒ ~call元は、[ `現在の~BYOB要請~view$RS内の要請された範囲 ]の外側には書込まない ◎ These asserts ensure that the caller does not write outside the requested range in the current BYOB request view.
- ~ABRUPT `ReadableByteStreamControllerRespond$A( %~stream.`controller$rS, %~chunk.`ByteLength^sl ) ◎ Perform ? ReadableByteStreamControllerRespond(stream.[[controller]], chunk.[[ByteLength]]).
- ~ELSE ⇒ ~ABRUPT `ReadableByteStreamControllerEnqueue$A( %~stream.`controller$rS, %~chunk ) ◎ Otherwise, perform ? ReadableByteStreamControllerEnqueue(stream.[[controller]], chunk).
以下に与える各~algoは、 上の[ `~byte読取り~support付きで設定しておく$RS~algoを介して初期化されたもの ]以外の `ReadableStream$I ~instanceには, 利用してはナラナイ。 ◎ The following algorithms must only be used on ReadableStream instances initialized via the above set up with byte reading support algorithm:
`ReadableStream$I %~stream 用の `現在の~BYOB要請~view@RS は、[ `ArrayBufferView$I / ~NULL ]であり,次の手続きにより決定される: ◎ The current BYOB request view for a ReadableStream stream is either an ArrayBufferView or null, determined by the following steps:
- ~Assert: %~stream.`controller$rS は `ReadableByteStreamController$I を`実装する$ ◎ Assert: stream.[[controller]] implements ReadableByteStreamController.
- %~BYOB要請 ~LET ~NOABRUPT `ReadableByteStreamControllerGetBYOBRequest$A( %~stream.`controller$rS ) ◎ Let byobRequest be ! ReadableByteStreamControllerGetBYOBRequest(stream.[[controller]]).
- ~RET %~BYOB要請 に応じて ⇒# ~NULL ならば ~NULL / ~ELSE_ %~BYOB要請.`view$bbrQ ◎ If byobRequest is null, then return null. ◎ Return byobRequest.[[view]].
仕様は、 `現在の~BYOB要請~view$RSに対しては,その`下層~buffer@~WEBIDLjs#buffersource-underlying-buffer$を[ `転送して@~WEBIDLjs#arraybuffer-transfer$はナラナイ/ `切離して@~WEBIDLjs#dfn-detach$はナラナイ ]。 ◎ Specifications must not transfer or detach the underlying buffer of the current BYOB request view.
注記: 実装は — 例えば,別の~threadから~memoryの中へ書込むよう求めるなら — 転送ngに等価な何かを行うこともできる。 が、 観測-可能な帰結が同じになることを保つため、[ `~chunkを~enqueueする$RS, `~closeする$RS ]~algoを実装する際に,少数の調整を施す必要があろう。 仕様の領分においては、[ 転送する/切離す ]ことは,単に許容されない。 ◎ Implementations could do something equivalent to transferring, e.g. if they want to write into the memory from another thread. But they would need to make a few adjustments to how they implement the enqueue and close algorithms to keep the same observable consequences. In specification-land, transferring and detaching is just disallowed.
仕様は、 `現在の~BYOB要請~view$RS %~view が ~NULL でないときは、 アリなら, %~view の`中へ~byte列を書込んで@~WEBIDLjs#arraybufferview-write$から `~chunkを~enqueueする$RS( %~view ) を~callするべきである。 仕様は、[ `~chunkを~enqueueする$RSに渡すためとして, 新たな `ArrayBufferView$I を`作成する@~WEBIDLjs#arraybufferview-create$ ]のは、[ %~view が ~NULL のとき ]または[ `現在の~BYOB要請~view$RSの`~byte長さ$BSより多くの~byteが, それら【どれ?】の手元に有るとき ]に限るベキである。 これは、 不必要な複製を避けて,当の~streamの`消費器$の望みをより良く尊重する。 ◎ Specifications should, when possible, write into the current BYOB request view when it is non-null, and then call enqueue with that view. They should only create a new ArrayBufferView to pass to enqueue when the current BYOB request view is null, or when they have more bytes on hand than the current BYOB request view's byte length. This avoids unnecessary copies and better respects the wishes of the stream’s consumer.
次に与える,`~byte列から~pullする$RS~algoは、 共通的な事例 — [ ある`下層~byte~source$を成す仕様~levelの表現として~serveする`~byte列$ %~byte列 ]から~byte列を導出する事例 — 用に,これらの要件を実装する。 それは、 保守的であり, %~byte列 内に【一部の】~byte列を残すことに注意 — %~byte列 から【全部を】積極的に`~chunkを~enqueueする$RSのではなく 【この~algoは、 入力 %~byte列 を改変する】 。 なので、 この~algoの~call元は,残りの~byteたちの個数を`背圧$用の通達として利用するよう求めることもあろう。 ◎ The following pull from bytes algorithm implements these requirements, for the common case where bytes are derived from a byte sequence that serves as the specification-level representation of an underlying byte source. Note that it is conservative and leaves bytes in the byte sequence, instead of aggressively enqueueing them, so callers of this algorithm might want to use the number of remaining bytes as a backpressure signal.
`ReadableStream$I %~stream の中へ `~byte列から~pullする@RS ときは、 所与の ( `~byte列$ %~byte列 ) に対し: ◎ To pull from bytes with a byte sequence bytes into a ReadableStream stream:
- ~Assert: %~stream .`controller$rS は `ReadableByteStreamController$I を`実装する$。 ◎ Assert: stream.[[controller]] implements ReadableByteStreamController.
- %可用な~size ~LET %~byte列 の`長さ$byte ◎ Let available be bytes’s length.
- %現在の要請~view ~LET %~stream の`現在の~BYOB要請~view$RS ◎ ↓
- %欲される~size ~LET %現在の要請~view に応じて ⇒# ~NULL ならば %可用な~size / ~ELSE_ %現在の要請~view の`~byte長さ$BS ◎ Let desiredSize be available. ◎ If stream’s current BYOB request view is non-null, then set desiredSize to stream’s current BYOB request view's byte length.
- %~pullする~size ~LET `min^op( %可用な~size, %欲される~size ) ◎ Let pullSize be the smaller value of available and desiredSize.
- %~pullした~byte列 ~LET %~byte列 を成す最初の %~pullする~size 個の~byte ◎ Let pulled be the first pullSize bytes of bytes.
- %~byte列 から最初の %~pullする~size 個の~byteを除去する ◎ Remove the first pullSize bytes from bytes.
-
~IF[ %現在の要請~view ~NEQ ~NULL ]: ◎ If stream’s current BYOB request view is non-null, then:
- `配列~buffer~viewの中へ~byte列を書込む$( %現在の要請~view, %~pullした~byte列 ) ◎ Write pulled into stream’s current BYOB request view.
- ~ABRUPT `ReadableByteStreamControllerRespond$A( %~stream .`controller$rS, %~pullする~size ) ◎ Perform ? ReadableByteStreamControllerRespond(stream.[[controller]], pullSize).
-
~ELSE: ◎ Otherwise,
- %~view ~SET `~buffer~sourceを~byte列から作成する$( `Uint8Array$I, %~pullした~byte列, %~stream に`関連な~realm$ ) ◎ Set view to the result of creating a Uint8Array from pulled in stream’s relevant Realm.
- ~ABRUPT `ReadableByteStreamControllerEnqueue$A( %~stream .`controller$rS, %~view ) ◎ Perform ? ReadableByteStreamControllerEnqueue(stream.[[controller]], view).
仕様は、 `ReadableStream$I を`~closeして@#readablestream-close$以降は、 その`現在の~BYOB要請~view$RSの中へ[ `~byte列を書込んで@~WEBIDLjs#arraybufferview-write$【!~WEBIDLjs#arraybuffer-write】はナラナイ/ `~byte列から~pullして@#readablestream-pull-from-bytes$はナラナイ ]。 ◎ Specifications must not write into the current BYOB request view or pull from bytes after closing the corresponding ReadableStream.
9.1.2. 読取n法
以下に与える~algoは、 任意な `ReadableStream$I ~instanceに利用できる — ~web開発者が作成したものも含め。 どれも,当の演算に特有な様々な仕方で失敗し得る — これらの失敗は、 ~callしている仕様が取扱うベキである。 ◎ The following algorithms can be used on arbitrary ReadableStream instances, including ones that are created by web developers. They can all fail in various operation-specific ways, and these failures should be handled by the calling specification.
`ReadableStream$I %~stream 用の `読取器を取得する@RS ときは ⇒ ~RET ~ABRUPT `AcquireReadableStreamDefaultReader$A( %~stream ) ◎ To get a reader for a ReadableStream stream, return ? AcquireReadableStreamDefaultReader(stream).\
結果は `ReadableStreamDefaultReader$I になる。 ◎ The result will be a ReadableStreamDefaultReader.
注記: これは、 %~stream がすでに`~lockされて$RSいるときは, 例外を投出することになる。 ◎ This will throw an exception if stream is already locked.
`ReadableStreamDefaultReader$I %読取器 から `~chunkを読取る@RSR ときは、 所与の ( `読取n要請$ %読取n要請 ) に対し ⇒ ~NOABRUPT `ReadableStreamDefaultReaderRead$A( %読取器, %読取n要請 ) ◎ To read a chunk from a ReadableStreamDefaultReader reader, given a read request readRequest, perform ! ReadableStreamDefaultReaderRead(reader, readRequest).
`ReadableStreamDefaultReader$I %読取器 から `すべての~byteを読取る@RSR ときは、 所与の ⇒# `~byte列$を受容する~algo %成功~手続き, ~JS値を受容する~algo %失敗~手続き ◎終 に対し ⇒ `読取n~loop$( %読取器, 新たな`~byte列$, %成功~手続き, %失敗~手続き ) ◎ To read all bytes from a ReadableStreamDefaultReader reader, given successSteps, which is an algorithm accepting a byte sequence, and failureSteps, which is an algorithm accepting a JavaScript value: read-loop given reader, a new byte sequence, successSteps, and failureSteps.
上~algoの目的における `読取n~loop@ は、 所与の ( %読取器, %~byte列, %成功~手続き, %失敗~手続き ) に対し,次を走らす: ◎ For the purposes of the above algorithm, to read-loop given reader, bytes, successSteps, and failureSteps:
-
%読取n要請 ~LET 次に挙げる`~item$sctを伴う,新たな`読取n要請$: ◎ Let readRequest be a new read request with the following items:
-
`~chunk手続き$rRは、 所与の ( %~chunk ) に対し: ◎ chunk steps, given chunk
- ~IF[ %~chunk は`有型~配列$~objでない ] ⇒# %失敗~手続き ( `TypeError$jE ); ~RET ◎ If chunk is not a Uint8Array object, call failureSteps with a TypeError and abort these steps.
- %~byte列 に[ %~chunk が表現する~byte列 ]を付加する ◎ Append the bytes represented by chunk to bytes.
-
`読取n~loop$( %読取器, %~byte列, %成功~手続き, %失敗~手続き ) ◎ Read-loop given reader, bytes, successSteps, and failureSteps.
注記: この再帰は、 直に実装すると,~stackを~overflowさせかねない。 実装は、 これを軽減する必要がある — 例えば,次のいずれかにより ⇒# この~algoの再帰的でない変種を利用する/ `小taskを~queueする$/ 下に注記されるように,各~byteをもっと直に読取る手法を利用する ◎ This recursion could potentially cause a stack overflow if implemented directly. Implementations will need to mitigate this, e.g. by using a non-recursive variant of this algorithm, or queuing a microtask, or using a more direct method of byte-reading as noted below.
- `~close手続き$rRは ⇒ %成功~手続き( %~byte列 ) ◎ close steps • Call successSteps with bytes.
- `~error手続き$rRは、 所与の ( %e ) に対し ⇒ %失敗~手続き( %e ) ◎ error steps, given e • Call failureSteps with e.
-
- ~NOABRUPT `ReadableStreamDefaultReaderRead$A( %読取器, %読取n要請 ) ◎ Perform ! ReadableStreamDefaultReaderRead(reader, readRequest).
注記: %読取器 は,それに対応している `ReadableStream$I に対し排他的な~accessを是認するので、 読取る方法を成す実際の仕組みは,観測され得ない。 実装は、 自身に好都合な もっと直接的な仕組みも利用できる。 `ReadableStreamDefaultReader$I に代えて `ReadableStreamBYOBReader$I を獲得して利用するか, 各~chunkに直に~accessするなど。 ◎ Because reader grants exclusive access to its corresponding ReadableStream, the actual mechanism of how to read cannot be observed. Implementations could use a more direct mechanism if convenient, such as acquiring and using a ReadableStreamBYOBReader instead of a ReadableStreamDefaultReader, or accessing the chunks directly.
`ReadableStreamDefaultReader$I %読取器 を `解放する@RSR ときは ⇒ ~NOABRUPT `ReadableStreamDefaultReaderRelease$A( %読取器 ) ◎ To release a ReadableStreamDefaultReader reader, perform ! ReadableStreamDefaultReaderRelease(reader).
`ReadableStreamDefaultReader$I %読取器 を `取消す@RSR ときは、 所与の ( %事由 ) に対し ⇒ 【~RET】 ~NOABRUPT `ReadableStreamReaderGenericCancel$A( %読取器, %事由 ) ◎ To cancel a ReadableStreamDefaultReader reader with reason, perform ! ReadableStreamReaderGenericCancel(reader, reason).\
返り値は、[ `undefined^jv で充足されるか, ある失敗~事由で却下される ]~promiseになる。 ◎ The return value will be a promise that either fulfills with undefined, or rejects with a failure reason.
`ReadableStream$I %~stream を `取消す@RS ときは、 所与の %事由 に対し ⇒ ~RET ~NOABRUPT `ReadableStreamCancel$A( %~stream, %事由 ) ◎ To cancel a ReadableStream stream with reason, return ! ReadableStreamCancel(stream, reason).\
返り値は、[ `undefined^jv で充足されるか, ある失敗~事由で却下される ]~promiseになる。 ◎ The return value will be a promise that either fulfills with undefined, or rejects with a failure reason.
`ReadableStream$I %~stream を `二又化する@RS ときは ⇒ ~RET ~ABRUPT `ReadableStreamTee$A( %~stream, ~T ) ◎ To tee a ReadableStream stream, return ? ReadableStreamTee(stream, true).
注記: `ReadableStreamTee$A の 2 個目の引数に ~T を渡すので、 返される 2 個目の`分岐$の`~chunk$は, 1 個目の`分岐$の`~chunk$から (~HTMLによる`直列化-可能$な~objの~frameworkを利用して) ~cloneされることになる。 これは、 一方の分岐の消費が他方に干渉することを防止する。 ◎ Because we pass true as the second argument to ReadableStreamTee, the second branch returned will have its chunks cloned (using HTML’s serializable objects framework) from those of the first branch. This prevents consumption of one of the branches from interfering with the other.
9.1.3. 自己検分
以下に挙げる述語は、 任意な `ReadableStream$I ~objに利用できる。 しかしながら — ~streamが`~lockされて$RSいるかどうか検査するときは別として — この直な自己検分は、 公な~JS~APIを介しては,アリでないことに注意。 なので、 他の仕様は,代わりに `§ 読取n法@#other-specs-rs-reading$ に与える~algoを利用するベキである (例えば,当の~streamは`読取n可能$RSかどうか~testする代わりに、 その`読取器を取得-$RSして例外を取扱うよう試みて)。 ◎ The following predicates can be used on arbitrary ReadableStream objects. However, note that apart from checking whether or not the stream is locked, this direct introspection is not possible via the public JavaScript API, and so specifications should instead use the algorithms in § 9.1.2 Reading. (For example, instead of testing if the stream is readable, attempt to get a reader and handle any exception.)
`ReadableStream$I %~stream は:
- 次を満たすとき, `読取n可能@RS とされる ⇒ %~stream.`state$rS ~EQ `readable^l ◎ A ReadableStream stream is readable if stream.[[state]] is "readable".
- 次を満たすとき, `~closeされ@RS たとされる ⇒ %~stream.`state$rS ~EQ `closed^l ◎ A ReadableStream stream is closed if stream.[[state]] is "closed".
- 次を満たすとき, `~errorした@RS とされる ⇒ %~stream.`state$rS ~EQ `errored^l ◎ A ReadableStream stream is errored if stream.[[state]] is "errored".
- 次を満たすとき, `~lockされて@RS いるとされる ⇒ 次の結果 ~EQ ~T ⇒ ~NOABRUPT `IsReadableStreamLocked$A( %~stream ) ◎ A ReadableStream stream is locked if ! IsReadableStreamLocked(stream) returns true.
-
次を満たすとき, `妨げられて@RS いるとされる ⇒ %~stream.`disturbed$rS ~EQ ~T ◎ A ReadableStream stream is disturbed if stream.[[disturbed]] is true.
注記: これは、 当の~streamは[ 一度でも読取られた/取消された ]かどうかを指示する。 これは、 ~web開発者が(間接的にも)~accessできる情報ではないので、 この節に与える他の述語より,なおさら控えめに諮るのが最善である。 そのようなわけで、 これに対し~platformの挙動が分岐することは,望ましくない。 ◎ This indicates whether the stream has ever been read from or canceled. Even more so than other predicates in this section, it is best consulted sparingly, since this is not information web developers have access to even indirectly. As such, branching platform behavior on it is undesirable.
9.2. 可書~stream
9.2.1. 作成と操作
`WritableStream$I ~obj %~stream を `設定しておく@WS ときは、 所与の:
- %書込n~algo
- `~chunk$~objを受容して~promiseを返す~algo
- %~close~algo
- ε / ~algo (省略時は ε )
- ~algoは、 ~promiseを返してもヨイ。
- %中止-~algo
- ε / ~algo (省略時は ε )
- ~algoは、 ~promiseを返してもヨイ。
- %限界水位
- 負でも `NaN^jv でもない ~number (省略時は 1 )
- %~size~algo
- ε / ~algo (省略時は ε )
- ~algoは、 `~chunk$~objを受容して~numberを返す。
に対し,次の手続きを遂行する:
◎ To set up a newly-created-via-Web IDL WritableStream object stream\ given\ an algorithm writeAlgorithm, an optional algorithm closeAlgorithm,\ an optional algorithm abortAlgorithm,\ an optional number highWaterMark (default 1),\ an optional algorithm sizeAlgorithm, perform the following steps.\ writeAlgorithm must be an algorithm that accepts a chunk object and returns a promise.\ If given, closeAlgorithm and abortAlgorithm may return a promise.\ If given, sizeAlgorithm must be an algorithm accepting chunk objects and returning a number;\ and if given, highWaterMark must be a non-negative, non-NaN number.- ~Assert: %~stream は`~Web~IDLを介して新たに作成した$ものである。 ◎ ↑
- %開始~algo ~LET 次を走らす~algo ⇒ ~RET `undefined^jv ◎ Let startAlgorithm be an algorithm that returns undefined.
-
%~close~algo包装体 ~LET 次を走らす~algo: ◎ Let closeAlgorithmWrapper be an algorithm that runs these steps:
- %結果 ~LET ~NULL ◎ ↓
- ~IF[ %~close~algo ~NEQ ε ] ⇒ %結果 ~SET %~close~algo() ⇒ 例外 %e が投出されたときは ⇒ ~RET `却下される~promise$( %e ) ◎ Let result be the result of running closeAlgorithm, if closeAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
- ~RET %結果 に応じて ⇒# `Promise$I であるならば %結果 / ~ELSE_ `解決される~promise$( `undefined^jv ) ◎ If result is a Promise, then return result. ◎ Return a promise resolved with undefined.
-
%中止-~algo包装体 ~LET 所与の ( %事由 ) に対し,次を走らす~algo: ◎ Let abortAlgorithmWrapper be an algorithm that runs these steps given reason:
- %結果 ~LET ~NULL ◎ ↓
- ~IF[ %中止-~algo ~NEQ ε ] ⇒ %結果 ~SET %中止-~algo( %事由 ) ⇒ 例外 %e が投出されたときは ⇒ ~RET `却下される~promise$( %e ) ◎ Let result be the result of running abortAlgorithm given reason, if abortAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
- ~RET %結果 に応じて ⇒# `Promise$I であるならば %結果 / ~ELSE_ `解決される~promise$( `undefined^jv ) ◎ If result is a Promise, then return result. ◎ Return a promise resolved with undefined.
- ~IF[ %~size~algo ~EQ ε ] ⇒ %~size~algo ~SET 次を走らす~algo ⇒ ~RET 1 ◎ If sizeAlgorithm was not given, then set it to an algorithm that returns 1.
- ~NOABRUPT `InitializeWritableStream$A( %~stream ) ◎ Perform ! InitializeWritableStream(stream).
- %制御器 ~LET `新たな$ `WritableStreamDefaultController$I ◎ Let controller be a new WritableStreamDefaultController.
- ~NOABRUPT `SetUpWritableStreamDefaultController$A( ↓ ) ⇒# %~stream, %制御器, %開始~algo, %書込n~algo, %~close~algo包装体, %中止-~algo包装体, %限界水位, %~size~algo ◎ Perform ! SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithmWrapper, abortAlgorithmWrapper, highWaterMark, sizeAlgorithm).
他の仕様は、[ 自身による `書込n~algo$V を構築するときに, 所与の`~chunk$から`並列的$に読取ることを避ける ]よう気を付けるベキである — そのような読取nは、 ~JSの “`完了まで走る$” 意味論に違反し得るので。 これは、[ `StructuredSerializeWithTransfer$A/ 当の~buffer~sourceにより`保持された~byte列の複製を取得する$/ `ArrayBuffer$I を`転送する@~WEBIDLjs#arraybuffer-transfer$ ]などの演算を利用して,所与の値の同期的な[ 複製または転送 ]を為すことで避けれる。 例外は,当の`~chunk$が `SharedArrayBuffer$I の場合であり、 そこでの並列的な変異は,~~避けようのない事実であると解される。 ◎ Other specifications should be careful when constructing their writeAlgorithm to avoid in parallel reads from the given chunk, as such reads can violate the run-to-completion semantics of JavaScript. To avoid this, they can make a synchronous copy or transfer of the given value, using operations such as StructuredSerializeWithTransfer, get a copy of the bytes held by the buffer source, or transferring an ArrayBuffer. An exception is when the chunk is a SharedArrayBuffer, for which it is understood that parallel mutations are a fact of life.
したがって,他の仕様から `WritableStream$I を作成するときは、 次の様な 2 段からなる処理nになる: ◎ Creating a WritableStream from other specifications is thus a two-step process, like so:
- %可書~stream ~LET `新たな$ `WritableStream$I ◎ Let writableStream be a new WritableStream.
- %可書~stream を`設定しておく$WS … ◎ Set up writableStream given….
注記: `WritableStream$I の下位classは、 その構築子~手続きの内側にて,コレを`設定しておく$WS演算を直に利用することになる。 ◎ Subclasses of WritableStream will use the set up operation directly on the this value inside their constructor steps.
以下に与える定義は、 上の`設定しておく$WS~algoを介して初期化されたもの以外の `WritableStream$I ~instanceには,利用してはナラナイ。 ◎ The following definitions must only be used on WritableStream instances initialized via the above set up algorithm:
`WritableStream$I %~stream を所与の~JS値 %e で `~errorにする@WS ときは ⇒ ~NOABRUPT `WritableStreamDefaultControllerErrorIfNeeded$A( %~stream . `controller$wS, %e ) ◎ To error a WritableStream stream given a JavaScript value e, perform ! WritableStreamDefaultControllerErrorIfNeeded(stream.[[controller]], e).
`WritableStream$I %~stream の `通達@WS は、 %~stream.`controller$wS.`abortController$wsdC の`通達$aCを指す。 各~仕様は、 この `AbortSignal$I に対し: ◎ The signal of a WritableStream stream is stream.[[controller]].[[abortController]]'s signal.\
- ~algoを[ `追加-$aB/`除去-$aB ]できる。 ◎ Specifications can add or remove algorithms to this AbortSignal,\
- `中止-済み$aBか否か, および その`中止-事由$aBに諮れる。 ◎ or consult whether it is aborted and its abort reason.
注記: 通例的な用法は、 `WritableStream$I を`設定しておいた$WS後に, その`通達$WSに[ 進行中な`下層~sink$への書込n演算があれば,それを中止する~algo ]を`追加-$aBすることである。 それから,`下層~sink$が応答したなら、 `書込n~algo$V の内側で,当の`通達$WSは`中止-済み$aBか否かを検査する — 中止-済みであるなら、 当の通達の`中止-事由$aBで返された`~promiseを却下する$。 ◎ The usual usage is, after setting up the WritableStream, add an algorithm to its signal, which aborts any ongoing write operation to the underlying sink. Then, inside the writeAlgorithm, once the underlying sink has responded, check if the signal is aborted, and reject the returned promise with the signal’s abort reason if so.
9.2.2. 書込n法
以下に与える~algoは、 任意な `WritableStream$I ~instanceに利用できる — ~web開発者が作成したものも含め。 どれも,当の演算に特有な様々な仕方で失敗し得る — これらの失敗は、 ~callしている仕様が取扱うベキである。 ◎ The following algorithms can be used on arbitrary WritableStream instances, including ones that are created by web developers. They can all fail in various operation-specific ways, and these failures should be handled by the calling specification.
`WritableStream$I %~stream 用の `書込器を取得する@WS ときは ⇒ ~RET ~ABRUPT `AcquireWritableStreamDefaultWriter$A( %~stream ) ◎ To get a writer for a WritableStream stream, return ? AcquireWritableStreamDefaultWriter(stream).\
結果は `WritableStreamDefaultWriter$I になる。 ◎ The result will be a WritableStreamDefaultWriter.
注記: これは、 %~stream がすでに~lockされている場合には, 例外を投出することになる。 ◎ This will throw an exception if stream is already locked.
`WritableStreamDefaultWriter$I %書込器 に `~chunkを書込む@WSW ときは、 所与の ( 値 %~chunk ) に対し ⇒ ~RET ~NOABRUPT `WritableStreamDefaultWriterWrite$A( %書込器, %~chunk ) ◎ To write a chunk to a WritableStreamDefaultWriter writer, given a value chunk, return ! WritableStreamDefaultWriterWrite(writer, chunk).
`WritableStreamDefaultWriter$I %書込器 を `解放する@WSW ときは ⇒ ~NOABRUPT `WritableStreamDefaultWriterRelease$A( %書込器 ) ◎ To release a WritableStreamDefaultWriter writer, perform ! WritableStreamDefaultWriterRelease(writer).
`WritableStream$I %~stream を `~closeする@WS ときは ⇒ ~RET ~NOABRUPT `WritableStreamClose$A( %~stream ) ◎ To close a WritableStream stream, return ! WritableStreamClose(stream).\
返り値は、[ `undefined^jv で充足されるか, ある失敗~事由で却下される ]~promiseになる。 ◎ The return value will be a promise that either fulfills with undefined, or rejects with a failure reason.
`WritableStream$I %~stream を `中止する@WS ときは、 所与の ( %事由 ) に対し ⇒ ~RET ~NOABRUPT `WritableStreamAbort$A( %~stream, %事由 ) ◎ To abort a WritableStream stream with reason, return ! WritableStreamAbort(stream, reason).\
返り値は、[ `undefined^jv で充足されるか, ある失敗~事由で却下される ]~promiseになる。 ◎ The return value will be a promise that either fulfills with undefined, or rejects with a failure reason.
9.3. 形式変換~stream
9.3.1. 作成と操作
`TransformStream$I %~stream を `設定しておく@TS ときは、 所与の:
- %形式変換~algo
- `~chunk$を受容する~algo
- ~algoは、 ~promiseを返してもヨイ。
- %書出n~algo
- ε / ~algo (省略時は ε )
- ~algoは、 ~promiseを返してもヨイ。
- %取消~algo
- ε / ~algo (省略時は ε )
- ~algoは、 ~promiseを返してもヨイ。
に対し,次の手続きを遂行する:
◎ To set up a newly-created-via-Web IDL TransformStream stream given\ an algorithm transformAlgorithm,\ an optional algorithm flushAlgorithm, and\ an optional algorithm cancelAlgorithm,\ perform the following steps.\ transformAlgorithm and, if given, flushAlgorithm and cancelAlgorithm, may return a promise.- ~Assert: %~stream は`~Web~IDLを介して新たに作成した$ものである。 ◎ ↑
- %可読~側の限界水位 ~LET 1 ◎ Let writableHighWaterMark be 1.
- %可読~側の~size~algo ~LET 次を走らす~algo ⇒ ~RET 1 ◎ Let writableSizeAlgorithm be an algorithm that returns 1.
- %可書~側の限界水位 ~LET 0 ◎ Let readableHighWaterMark be 0.
- %可書~側の~size~algo ~LET 次を走らす~algo ⇒ ~RET 1 ◎ Let readableSizeAlgorithm be an algorithm that returns 1.
-
%形式変換~algo包装体 ~LET 所与の ( 値 %~chunk ) に対し,次を走らす~algo: ◎ Let transformAlgorithmWrapper be an algorithm that runs these steps given a value chunk:
- %結果 ~LET %形式変換~algo( %~chunk ) ⇒ 例外 %e が投出されたときは ⇒ ~RET `却下される~promise$( %e ) ◎ Let result be the result of running transformAlgorithm given chunk. If this throws an exception e, return a promise rejected with e.
- ~RET %結果 に応じて ⇒# `Promise$I であるならば %結果 / ~ELSE_ `解決される~promise$( `undefined^jv ) ◎ If result is a Promise, then return result. ◎ Return a promise resolved with undefined.
-
%書出n~algo包装体 ~LET 次を走らす~algo: ◎ Let flushAlgorithmWrapper be an algorithm that runs these steps:
- %結果 ~LET ~NULL ◎ ↓
- ~IF[ %書出n~algo ~NEQ ε ] ⇒ %結果 ~SET %書出n~algo() ⇒ 例外 %e が投出されたときは ⇒ ~RET `却下される~promise$( %e ) ◎ Let result be the result of running flushAlgorithm, if flushAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
- ~RET %結果 に応じて ⇒# `Promise$I であるならば %結果 / ~ELSE_ `解決される~promise$( `undefined^jv ) ◎ If result is a Promise, then return result. ◎ Return a promise resolved with undefined.
-
%取消~algo包装体 ~LET 所与の ( %事由 ) に対し,次を走らす~algo: ◎ Let cancelAlgorithmWrapper be an algorithm that runs these steps given a value reason:
- %結果 ~LET ~NULL ◎ ↓
- ~IF[ %取消~algo ~NEQ ε ] ⇒ %結果 ~SET %取消~algo( %事由 ) ⇒ 例外 %e が投出されたときは ⇒ ~RET `却下される~promise$( %e ) ◎ Let result be the result of running cancelAlgorithm given reason, if cancelAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
- ~RET %結果 に応じて ⇒# `Promise$I であるならば %結果 / ~ELSE_ `解決される~promise$( `undefined^jv ) ◎ If result is a Promise, then return result. ◎ Return a promise resolved with undefined.
- %開始~promise ~LET `解決される~promise$( `undefined^jv ) ◎ Let startPromise be a promise resolved with undefined.
- ~NOABRUPT `InitializeTransformStream$A( ↓ ) ⇒# %~stream, %開始~promise, %可読~側の限界水位, %可読~側の~size~algo, %可書~側の限界水位, %可書~側の~size~algo ◎ Perform ! InitializeTransformStream(stream, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm).
- %制御器 ~LET `新たな$ `TransformStreamDefaultController$I ◎ Let controller be a new TransformStreamDefaultController.
- ~NOABRUPT `SetUpTransformStreamDefaultController$A( ↓ ) ⇒# %~stream, %制御器, %形式変換~algo包装体, %書出n~algo包装体, %取消~algo包装体 ◎ Perform ! SetUpTransformStreamDefaultController(stream, controller, transformAlgorithmWrapper, flushAlgorithmWrapper, cancelAlgorithmWrapper).
他の仕様は、[ 自身による `形式変換~algo$V を構築するときに, 所与の`~chunk$から`並列的$に読取ることを避ける ]よう気を付けるベキである — そのような読取nは、 ~JSの “`完了まで走る$” 意味論に違反し得るので。 これは、[ `StructuredSerializeWithTransfer$A/ 当の~buffer~sourceにより`保持された~byte列の複製を取得する$/ `ArrayBuffer$I を`転送する@~WEBIDLjs#arraybuffer-transfer$ ]などの演算を利用して,所与の値の同期的な[ 複製または転送 ]を為すことで避けれる。 例外は,当の`~chunk$が `SharedArrayBuffer$I の場合であり、 そこでの並列的な変異は,~~避けようのない事実であると解される。 ◎ Other specifications should be careful when constructing their transformAlgorithm to avoid in parallel reads from the given chunk, as such reads can violate the run-to-completion semantics of JavaScript. To avoid this, they can make a synchronous copy or transfer of the given value, using operations such as StructuredSerializeWithTransfer, get a copy of the bytes held by the buffer source, or transferring an ArrayBuffer. An exception is when the chunk is a SharedArrayBuffer, for which it is understood that parallel mutations are a fact of life.
したがって,他の仕様から `TransformStream$I を作成するときは、 次の様な 2 段からなる処理nになる: ◎ Creating a TransformStream from other specifications is thus a two-step process, like so:
- %形式変換~stream ~LET `新たな$ `TransformStream$I ◎ Let transformStream be a new TransformStream.
- %形式変換~stream を`設定しておく$TS … ◎ Set up transformStream given….
注記: `TransformStream$I の下位classは、 その構築子~手続きの内側にて,コレを`設定しておく$TS演算を直に利用することになる。 ◎ Subclasses of TransformStream will use the set up operation directly on the this value inside their constructor steps.
`恒等変換~streamを作成する@ ときは: ◎ To create an identity TransformStream:
- %形式変換~stream ~LET `新たな$ `TransformStream$I ◎ Let transformStream be a new TransformStream.
- %形式変換~algo ~LET 所与の ( %~chunk ) に対し,次を走らす~algo ⇒ %形式変換~stream に`~chunkを~enqueueする$TS( %~chunk ) ◎ ↓
- %形式変換~stream を`設定しておく$TS( %形式変換~algo ) ◎ Set up transformStream with transformAlgorithm set to an algorithm which, given chunk, enqueues chunk in transformStream.
- ~RET %形式変換~stream ◎ Return transformStream.
以下に与える~algoは、 上の`設定しておく$TS~algoを介して初期化されたもの以外の `TransformStream$I ~instanceには,利用してはナラナイ。 それらは、 通例的に[ `形式変換~algo$V / `書出n~algo$V ]の一部として~callされる。 ◎ The following algorithms must only be used on TransformStream instances initialized via the above set up algorithm. Usually they are called as part of transformAlgorithm or flushAlgorithm.
`TransformStream$I %~stream に `~chunkを~enqueueする@TS ときは、 所与の ( ~JS値 %~chunk ) に対し ⇒ ~NOABRUPT `TransformStreamDefaultControllerEnqueue$A( %~stream.`controller$tS, %~chunk ) ◎ To enqueue the JavaScript value chunk into a TransformStream stream, perform ! TransformStreamDefaultControllerEnqueue(stream.[[controller]], chunk).
`TransformStream$I %~stream を `終了する@TS ときは ⇒ ~NOABRUPT `TransformStreamDefaultControllerTerminate$A( %~stream.`controller$tS ) ◎ To terminate a TransformStream stream, perform ! TransformStreamDefaultControllerTerminate(stream.[[controller]]).
`TransformStream$I %~stream を 所与の~JS値 %e で `~errorにする@TS ときは ⇒ ~NOABRUPT `TransformStreamDefaultControllerError$A( %~stream.`controller$tS, %e ) ◎ To error a TransformStream stream given a JavaScript value e, perform ! TransformStreamDefaultControllerError(stream.[[controller]], e).
9.3.2. ~custom~classの中への包装-法
他の仕様は、 ~customな`形式変換~stream$を定義するときは, `TransformStream$I ~interfaceを直に下位class化したくないと求めることもあろう。 新たな~classが必要なときは、 代わりに次の~mixinを利用して, 自前の独立な~Web~IDL~interfaceを作成できる: ◎ Other specifications which mean to define custom transform streams might not want to subclass from the TransformStream interface directly. Instead, if they need a new class, they can create their own independent Web IDL interfaces, and use the following mixin:
interface mixin `GenericTransformStream@I { readonly attribute `ReadableStream$I `readable$gts; readonly attribute `WritableStream$I `writable$gts; };
`GenericTransformStream$I ~mixinを`内包-$する各`~platform~obj$には、 実際の `TransformStream$I を与える `形式変換@GRS が結付けられる。 ◎ Any platform object that includes the GenericTransformStream mixin has an associated transform, which is an actual TransformStream.
`GenericTransformStream$I ~mixinを`内包-$することで、 当の~IDL~interfaceは,適切な[ `readable$gts, `writable$gts ]~propを有することになる。 結果の~interfaceの挙動を~custom化するためには、 その構築子(あるいは他の初期化~code)において,次が行われなければナラナイ ⇒ 当の~instanceの`形式変換$GRSを新たな `TransformStream$I に設定してから,`設定しておく$TS — ~custom化は、 その引数[ `形式変換~algo$V, 省略可能な`書出n~algo$V ]を介して,適切に行う。 ◎ Including the GenericTransformStream mixin will give an IDL interface the appropriate readable and writable properties. To customize the behavior of the resulting interface, its constructor (or other initialization code) must set each instance’s transform to a new TransformStream, and then set it up with appropriate customizations via the transformAlgorithm and optionally flushAlgorithm arguments.
注記: ~web~platformにおける,この~patternの既存の例には、 次が挙げられる ⇒# `CompressionStream$I `COMPRESSION$r / `TextDecoderStream$I `ENCODING$r ◎ Note: Existing examples of this pattern on the web platform include CompressionStream and TextDecoderStream. [COMPRESSION] [ENCODING]
注記: 基底 `TransformStream$I ~classが供するものを超える~APIは必要ない場合、 それを包装する~classを作成する必要も無い。 そのような包装体を要する~~誘因として最も共通的なのは, ~customな`構築子~手続き$が必要なときである — 当の概念的な形式変換~streamは、 そのように構築されることは意味されないならば, `TransformStream$I を直に利用することで~~十分になる。 ◎ There’s no need to create a wrapper class if you don’t need any API beyond what the base TransformStream class provides. The most common driver for such a wrapper is needing custom constructor steps, but if your conceptual transform stream isn’t meant to be constructed, then using TransformStream directly is fine.
9.4. 他の~stream~pair
上で論じた`形式変換~stream$は別として、 他の仕様は,[ `可読~stream$, `可書~stream$ ]の~pairを作成することが多い。 この節は、 そのような状況~用に,いくつかの指導を与える。 ◎ Apart from transform streams, discussed above, specifications often create pairs of readable and writable streams. This section gives some guidance for such situations.
そのような どの事例においても,仕様は、[ 当の~streamを公開する 2 つの~prop ]の名前には[ `readable^m, `writable^m ]を利用するベキであり,他の名前([ `input^c, `output^c ]や[ `readableStream^c, `writableStream^c ]など)は利用するベキでない。 また、 ~methodその他の~prop以外の手段を利用して,当の~streamに~accessするベキでない。 ◎ In all such cases, specifications should use the names readable and writable for the two properties exposing the streams in question. They should not use other names (such as input/output or readableStream/writableStream), and they should not use methods or other non-property means of access to the streams.
9.4.1. 二重化~stream
最も共通的な[ `readable^m, `writable^m ]~pairは, `二重化~stream@ ( `duplex stream^en )であり、 そこでは[ 可読, 可書 ]~streamは,共有される同じ資源の 2 つの側を表現する — ~socket, 接続, ~device, など。 ◎ The most common readable/writable pair is a duplex stream, where the readable and writable streams represent two sides of a single shared resource, such as a socket, connection, or device.
二重化~streamを指定するために考慮する,最も込み入ったものは、[ 可読~側を`取消す$/可書~側を[ ~closeする/`中止する$ ]]様な演算を取扱う方法である。 一方の側が他方の側に影響iしないような演算で,二重化~streamを “半ば~open” したままにすることは、 イミを成すかもしれない。 あるいは、 それによる効果を他の側へ引継ぐのが最善かもしれない — 例:[ 可読~側の `取消~algo@#readablestream-set-up-cancelalgorithm$V が,可書~側を`~closeする$WSことになる ]よう指定するなど。 ◎ The trickiest thing to consider when specifying duplex streams is how to handle operations like canceling the readable side, or closing or aborting the writable side. It might make sense to leave duplex streams "half open", with such operations one one side not impacting the other side. Or it might be best to carry over their effects to the other side, e.g. by specifying that your readable side’s cancelAlgorithm will close the writable side.
二重化~streamの基本的な例は、 `§ 同じ下層~資源を包装する { 可読, 可書 } ~stream~pair@#example-both$ に見出せる。 それは、 (仕様の注釈文ではなく)~JSを通して作成され,この引継ぐ挙動を例示する。 ◎ A basic example of a duplex stream, created through JavaScript instead of through specification prose, is found in § 10.8 A { readable, writable } stream pair wrapping the same underlying resource. It illustrates this carry-over behavior.
二重化~streamを非同期的に獲得する必要がある場合(例:接続を確立することを介して)、 その作成を取扱う方法も,別の考慮としてある。 ここで選好される~patternは、[ 実際の二重化~stream~objで充足するような~promise ]を返す~propを伴う,構築-可能な~classである。 その二重化~stream~objは、 非同期的にしか可用にならない情報(例:接続~data)も公開できる。 この容器~classは、 便利~API — 個々の側に限り~closeする代わりに接続を全体~closeする関数など — を供せる。 ◎ Another consideration is how to handle the creation of duplex streams which need to be acquired asynchronously, e.g. via establishing a connection. The preferred pattern here is to have a constructible class with a promise-returning property that fulfills with the actual duplex stream object. That duplex stream object can also then expose any information that is only available asynchronously, e.g. connection data. The container class can then provide convenience APIs, such as a function to close the entire connection instead of only closing individual sides.
この,より複階的な型の二重化~streamの例は、 まだ仕様~化されていない `WebSocketStream^I である。 その `説明書き@https://github.com/ricea/websocketstream-explainer/blob/master/README.md$, `設計~注記@https://docs.google.com/document/d/1La1ehXw76HP6n1uUeks-WJGFgAnpX2tCjKts7QFJ57Y/edit#$ を見よ。 ◎ An example of this more complex type of duplex stream is the still-being-specified WebSocketStream. See its explainer and design notes.
二重化~streamは、[ `readable^m / `writable^m ]~propの契約を順守するので, `pipeThrough()$rs とともに利用できる。 これは,常にイミを成すわけではないが、 下層の資源が何らかの類の形式変換nを~~実際に遂行している事例では,イミを成すこともある。 ◎ Because duplex streams obey the readable/writable property contract, they can be used with pipeThrough(). This doesn’t always make sense, but it could in cases where the underlying resource is in fact performing some sort of transformation.
任意な~WebSocket用には、 ~WebSocketから導出された二重化~streamを通して~pipeしてもイミを成さない。 しかしながら,~WebSocket~serverが[ 流入ng~messageに対し,[ 同じ~dataを,何らかの形式変換された形で送信し戻す ]よう応答する ]よう特定的に書かれている場合、 これは,有用かつ簡便にもなり得る。 ◎ For an arbitrary WebSocket, piping through a WebSocket-derived duplex stream doesn’t make sense. However, if the WebSocket server is specifically written so that it responds to incoming messages by sending the same data back in some transformed form, then this could be useful and convenient.
9.4.2. 端点~pair
別の型の[ `readable^m, `writable^m ]~pairは、 `端点~pair@ である。 これらの事例では、[ 可読, 可書 ]~streamは,より長い~pipelineの両端を表現する — ~web開発者の~codeが,その途中に`形式変換~stream$を挿入する意図nの下で。 ◎ Another type of readable/writable pair is an endpoint pair. In these cases the readable and writable streams represent the two ends of a longer pipeline, with the intention that web developer code insert transform streams into the middle of them.
`createEndpointPair()^c は、 ~web~platformが供した関数とする。 ~web開発者は、 次の様な~codeを書くことになろう: ◎ Assuming we had a web-platform-provided function createEndpointPair(), web developers would write code like so:
const { %readable, %writable } = createEndpointPair(); %readable.pipeThrough(new TransformStream(...)).pipeTo(%writable);
`WebRTC Encoded Transform^cite の `RTCRtpScriptTransformer@https://w3c.github.io/webrtc-encoded-transform/#rtcrtpscripttransformer$I ~interfaceは、 `readable^m, `writable^m 両~属性を有する例である。 ◎ WebRTC Encoded Transform is an example of this technique, with its RTCRtpScriptTransformer interface which has both readable and writable attributes.
そのような端点~pairが[ `readable^m / `writable^m ]~propの契約を順守していようが、[ それを `pipeThrough()$rs へ渡すことがイミを成す ]ことは決してない。 ◎ Despite such endpoint pairs obeying the readable/writable property contract, it never makes sense to pass them to pipeThrough().
9.5. ~pipe法
`ReadableStream$I %可読 を `WritableStream$I %可書 へ `~pipeする@RS ときは、 所与の:
- %~closeを防止するか
- 真偽値 (省略時は ~F )
- %中止-を防止するか
- 真偽値 (省略時は ~F )
- %取消-を防止するか
- 真偽値 (省略時は ~F )
- %通達
- `undefined^jv / `AbortSignal$I (省略時は `undefined^jv )
に対し,次の手続きを遂行する — これは、 ~pipeが[ 完了したとき充足する/ 失敗したとき例外で却下する ]ことになる `Promise$I を返す:
◎ The result of a ReadableStream readable piped to a WritableStream writable, given\ an optional boolean preventClose (default false),\ an optional boolean preventAbort (default false),\ an optional boolean preventCancel (default false),\ and an optional AbortSignal signal,\ is given by performing the following steps.\ They will return a Promise that fulfills when the pipe completes, or rejects with an exception if it fails.- ~Assert: ~NOABRUPT `IsReadableStreamLocked$A( %可読 ) ~EQ ~F ◎ Assert: ! IsReadableStreamLocked(readable) is false.
- ~Assert: ~NOABRUPT `IsWritableStreamLocked$A( %可書 ) ~EQ ~F ◎ Assert: ! IsWritableStreamLocked(writable) is false. ◎ ↑Let signalArg be signal if signal was given, or undefined otherwise.
- ~RET ~NOABRUPT `ReadableStreamPipeTo$A( ↓ ) ⇒# %可読, %可書, %~closeを防止するか, %中止-を防止するか, %取消-を防止するか, %通達 ◎ Return ! ReadableStreamPipeTo(readable, writable, preventClose, preventAbort, preventCancel, signalArg).
注記: 【この段落の内容 — 英文に特有な言い回しに関する注記 — は、省略する。】 ◎ If one doesn’t care about the promise returned, referencing this concept can be a bit awkward. The best we can suggest is "pipe readable to writable".
`ReadableStream$I %可読 を `TransformStream$I %形式変換 を `通して~pipeする@RS ときは、 所与の:
- %~closeを防止するか
- 真偽値 (省略時は ~F )
- %中止-を防止するか
- 真偽値 (省略時は ~F )
- %取消-を防止するか
- 真偽値 (省略時は ~F )
- %通達
- `AbortSignal$I (省略時は `undefined^jv )
に対し,次の手続きを遂行する — これは、 %形式変換 の`可読~側$を返す:
◎ The result of a ReadableStream readable piped through a TransformStream transform, given\ an optional boolean preventClose (default false),\ an optional boolean preventAbort (default false),\ an optional boolean preventCancel (default false),\ and an optional AbortSignal signal,\ is given by performing the following steps.\ The result will be the readable side of transform.- ~Assert: ~NOABRUPT `IsReadableStreamLocked$A( %可読 ) ~EQ ~F ◎ Assert: ! IsReadableStreamLocked(readable) is false.
- ~Assert: ~NOABRUPT `IsWritableStreamLocked$A( %形式変換.`writable$tS ) ~EQ ~F ◎ Assert: ! IsWritableStreamLocked(transform.[[writable]]) is false. ◎ ↑Let signalArg be signal if signal was given, or undefined otherwise.
- %~promise ~LET ~NOABRUPT `ReadableStreamPipeTo$A( ↓ ) ⇒# %可読, %形式変換.`writable$tS, %~closeを防止するか, %中止-を防止するか, %取消-を防止するか, %通達 ◎ Let promise be ! ReadableStreamPipeTo(readable, transform.[[writable]], preventClose, preventAbort, preventCancel, signalArg).
- %~promise.`PromiseIsHandled^sl ~SET ~T ◎ Set promise.[[PromiseIsHandled]] to true.
- ~RET %形式変換.`readable$tS ◎ Return transform.[[readable]].
`ReadableStream$I %~stream 用の `~proxyを作成する@RS ときは、次の手続きを遂行する — その結果は %~stream から~dataを~pullする新たな `ReadableStream$I ~objになり,それに伴い %~stream は即時に[ `~lockされて$RSいる ]~AND[ `妨げられて$RSいる ]を満たすようになる: ◎ To create a proxy for a ReadableStream stream, perform the following steps. The result will be a new ReadableStream object which pulls its data from stream, while stream itself becomes immediately locked and disturbed.
- %恒等変換 ~LET `恒等変換~streamを作成する$() ◎ Let identityTransform be the result of creating an identity TransformStream.
- ~RET %~stream を %恒等変換 を`通して~pipeする$RS ◎ Return the result of stream piped through identityTransform.
10. ~streamを作成する例
`この節とその各下位節すべては、規範的でない。^em ◎ This section, and all its subsections, are non-normative.
これまでの例では、 ~streamを利用する方法に力点を置いていた。 ここでは、[ `ReadableStream$I / `WritableStream$I / `TransformStream$I ]の構築子を利用して,~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, WritableStream, and TransformStream constructors.
10.1. 下層~push~sourceを伴う可読~stream(背圧~supportなし)
次の関数は、 `WebSocket$I ~instance `WEBSOCKETS$r を包装する可読~streamを作成する。 それは、 背圧~通達を~supportしない`~push~source$である。 【! It illustrates how,】 `~push~source$に順応させるとき、 通例的に,ほとんどの作業は `start()$usc ~methodにて起きるようにされる。 ◎ The following function creates readable streams that wrap WebSocket instances [WEBSOCKETS], 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() method.
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【!The WebSocket errored!】)); }, 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側の~memory内に保持する ]ことなく,単独の~message内に転送できるような。 この目標を成遂げるためには、 個々の~web~socket~message自身が `ReadableStream$I ~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.
更なる背景0は、 `この論点@https://github.com/w3c/webrtc-pc/issues/1732#issuecomment-358428651$ を見よ。 ◎ For more background, see this discussion.
10.2. 下層~push~sourceを伴う可読~stream(背圧~supportあり)
次の関数は、 “背圧~socket” を包装する`可読~stream$を返す — 背圧~socketは、 ~web~socketと同じ~APIを有する仮説上の~objであるが,[ `readStop^m / `readStart^m ]~methodにより,~dataの流れを[ 静止する/再開する ]能も供する。 この例では、 そうすることで,背圧を~supportする`下層~source$に背圧を適用する方法を示す。 ◎ 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は満杯なので,下層~sourceへ背圧~通達を伝播させる。 ◎ 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【!The socket errored!】)); }, 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.
10.3. 下層~push~sourceを伴う可読~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(() => {
/*
処理待ち~BYOB要請( `byobRequest$rbsc )がないときでも,
%socket は読取n可能になり得るので、
両~事例とも取扱う必要がある。
◎
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);
if (%bytesRead === 0) {
%controller.close();
}
%controller.byobRequest.respond(%bytesRead);
} else {
const %buffer = new ArrayBuffer(%DEFAULT_CHUNK_SIZE);
%bytesRead = %socket.readInto(%buffer, 0, %DEFAULT_CHUNK_SIZE);
if (%bytesRead === 0) {
%controller.close();
} else {
%controller.enqueue(new Uint8Array(%buffer, 0, %bytesRead));
}
}
if (%bytesRead === 0) {
return;
}
return readRepeatedly();
});
}
},
cancel() {
%socket.close();
}
});
}
この関数から返される `ReadableStream$I ~instanceは、 今や,前に示したすべての便益と但し書きを伴うような `~BYOB読取器$を配給できる。 ◎ ReadableStream instances returned from this function can now vend BYOB readers, with all of the aforementioned benefits and caveats.
10.4. 下層~pull~sourceを伴う可読~stream
次の関数は、 (それ自身 直に C 言語の[ `fopen()^c, `fread()^c, `fclose()^c ]組みへ対応付けている) `Node.js ~file~system~API@https://nodejs.org/api/fs.html$ の各部位を包装する,`可読~stream$を返す。 ~fileは `~pull~source$の代表的な例である。 `~push~source$を伴う例とは対照的に,ここでのほとんどの作業は、 `start()$usc 関数の開始時ではなく, `pull()$usc 関数~内でその時々に起きることに注意。 ◎ 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("fs").promises; const %CHUNK_SIZE = 1024; function makeReadableFileStream(%filename) { let %fileHandle; let %position = 0; return new ReadableStream({ async start() { %fileHandle = await %fs.open(%filename, "r"); }, async pull(%controller) { const %buffer = new Uint8Array(%CHUNK_SIZE); const { %bytesRead } = await %fileHandle.read(%buffer, 0, %CHUNK_SIZE, %position); if (%bytesRead === 0) { await %fileHandle.close(); %controller.close(); } else { %position += %bytesRead; %controller.enqueue(%buffer.subarray(0, %bytesRead)); } }, cancel() { return %fileHandle.close(); } }); }
これを利用すれば、 前に~socketに対しできたときとちょうど~~同じく, ~file用の可読~streamを作成して利用できるようになる。 ◎ We can then create and use readable streams for files just as we could before for sockets.
10.5. 下層~pull~sourceを伴う可読~byte~stream
次の関数は,再び `Node.js ~file~system~API@https://nodejs.org/api/fs.html$ を利用して`可読~byte~stream$を返すが、 今度は,~fileを複製することなく効率的に読取れるようにする。 それは、 予め決定-済みな~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("fs").promises;
const %DEFAULT_CHUNK_SIZE = 1024;
function makeReadableByteFileStream(%filename) {
let %fileHandle;
let %position = 0;
return new ReadableStream({
type: "bytes",
async start() {
%fileHandle = await %fs.open(%filename, "r");
},
async 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;
const { %bytesRead } = await %fileHandle.read(%v, 0, %v.byteLength, %position);
if (%bytesRead === 0) {
await %fileHandle.close();
%controller.close();
%controller.byobRequest.respond(0);
} else {
%position += %bytesRead;
%controller.byobRequest.respond(%bytesRead);
}
},
cancel() {
return %fileHandle.close();
},
autoAllocateChunkSize: %DEFAULT_CHUNK_SIZE
});
}
これを使えば、 返された `ReadableStream$I 用の`~BYOB読取器$を作成して利用できるようになる。 一方で、 それを[ 通例通り,単純かつ汎用な方式 ]で利用して,`既定の読取器$を作成することもできる。 [ 低~levelな,ここに示す`下層~byte~source$に対する~byteの追跡 ]と[ より高~levelな,~chunkに基づく`既定の読取器$による消費 ]との間の順応は、 すべて,~stream実装により自動的に~careされる。 `autoAllocateChunkSize$usc ~optionを介する自動-割振り特能は、[ `下層~push~sourceを伴う可読~byte~stream(背圧~supportなし)$sec のように手動的に分岐する ]のに比して,必要な~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 § 10.3 A readable byte stream with an underlying push source (no backpressure support).
10.6. 背圧や成功の通達を伴わない可書~stream
次の関数は、 `WebSocket$I `WEBSOCKETS$r を包装する`可書~stream$を返す。 ~web~socketは[ 所与の~dataの`~chunk$が いつ成功裡に送信されたか ]を伝える仕方を供さない(~~扱いにくい `bufferedAmount$m の~pollingを行わない限り — それについては,読者への宿題として残しておく)。 そのようなわけで、 この可書~streamの`生産器$には,[ 正確aな背圧~通達や 書込nの成否 ]を通信する能は無い。 すなわち、 その`書込器$の[ `write()$dw ~method / `ready$dw 取得子 ]から返される~promiseは, 常に即時に充足されることになる。 ◎ The following function returns a writable stream that wraps a WebSocket [WEBSOCKETS]. 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【!The WebSocket errored!】));
%ws.onclose = null;
};
%ws.onclose = () => {
%controller.error(new Error(`接続は不意に~serverにより~closeされました^l【!The server closed the connection unexpectedly】));
}
return new Promise(%resolve => %ws.onopen = %resolve);
},
write(%chunk) {
%ws.send(%chunk);
/*
即時に返る
— ~web~socketでは,書込nがいつ完了するかを伝える容易な仕方はないので。
◎
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【!The connection was not closed cleanly】));
}
};
%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の中に包装することについては、 `前述の注記@#note-web-socket-wrapping-examples$ を見よ。 ◎ See the earlier note about this style of wrapping web sockets into streams.
10.7. 背圧や成功の通達を伴う可書~stream
次の関数は、 `Node.js ~file~system~API@https://nodejs.org/api/fs.html$ (それ自身,直に C 言語の[ `fopen^c, `fwrite^c, `fclose^c ]組みへ対応付けている)の各部位を包装する,`可書~stream$を返す。 その~APIは,所与の書込nが成功したときにそれを伝える仕方を供するので、 この~streamは,個々の書込nの成否も込みで`背圧$通達を通信できる。 ◎ 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("fs").promises; function makeWritableFileStream(%filename) { let %fileHandle; return new WritableStream({ async start() { %fileHandle = await %fs.open(%filename, "w"); }, write(%chunk) { return %fileHandle.write(%chunk, 0, %chunk.length); }, close() { return %fileHandle.close(); }, abort() { return %fileHandle.close(); } }); }
この関数を利用すれば、 ~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【!To stream, or not to stream\n】); %writer.write(`それが~~問題だ。\n^l【!That is the question\n】); %writer.close() .then( () => console.log( `~chunkたちは書込まれ, ~streamは成功裡に~closeされました^l【!chunks written and stream closed successfully!】 )) .catch(%e => console.error(%e));
特定0の `fileHandle.write^c ~callにて時間がかかる場合、 返される~promiseは,後で充足されることになることに注意。 当面の間は、 追加的な書込nを~queueしておける — それらは、 ~streamの内部~queueに格納される。 この~queueにおける`~chunk$たちの累積により、 ~streamは `ready$dw 取得子が処理待ち~promiseを返すように変化し得る — それは、 ~streamの`生産器$に[ アリなら手を止めて書込みを停止することで,便益が得られる ]ことを通達する ◎ Note that if a particular call to fileHandle.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が書込nを~queueしておく仕方が,とりわけ重要になる
— `fileHandle.write()@https://nodejs.org/api/fs.html#fs_filehandle_write_buffer_offset_length_position$c
にて文書化されたとおり,
~promiseを待機することなく,同じ~file上で
`fileHandle.write()^c を複数回 利用することは安全でない
ので。
しかしながら, `makeWritableFileStream^c 関数を書くときは、
それについて心配する必要はない
— ~stream実装が,次を保証してくれるので
⇒
`下層~sink$の `write()$usk ~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 fileHandle.write, "it is unsafe to use filehandle.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!
10.8. 同じ下層~資源を包装する { 可読, 可書 } ~stream~pair
次の関数は `{ readable, writable }^c の形による~objを返す — [ `readable^m ~propは可読~stream / `writable^m ~propは可書~stream ]を包含していて,両~streamとも同じ下層~web~socket資源を包装するような。 これは、 本質的には,次の 2 つを組合せる ⇒# `下層~push~sourceを伴う可読~stream(背圧~supportなし)$sec, `背圧や成功の通達を伴わない可書~stream$sec ◎ 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 § 10.1 A readable stream with an underlying push source (no backpressure support) and § 10.6 A writable stream with no backpressure or success signals.
~JS~classを利用して、 再利用-可能な[ `下層~sink$/`下層~source$ ]の抽象-化を作成する方法を例示する: ◎ 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, %reasonString) { 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を利用して,~remote~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【!Hello】); %writer.write(`web socket さん。^l【!web socket】); %reader.read().then(({ %value, %done }) => { console.log(`こちらこそ、どうもです:^l【!The web socket says: 】, %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の中に包装することについては、 `前述の注記@#note-web-socket-wrapping-examples$ を見よ。 ◎ See the earlier note about this style of wrapping web sockets into streams.
10.9. ~template内の~tagを置換する形式変換~stream
~dataが成す~stream上の~tagたちを変数で置換sすることが有用になることは多い
— 置換される必要がある各部が、
総~data~sizeに比較して小さい所では。
この例は、
それを行う単純な仕方を呈示する。
それは、
文字列を文字列に対応付ける
— 例えば,
`Time: {{time}} Message: {{message}}^l
の様な~templateを
`Time: 15:36 Message: hello^l
の様に形式変換して(
`LipFuzzTransformer^I には、
%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 ~prop内に累積されることになる。 ◎ 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 property 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$I 構築子に渡される`形式変換器$を定義する。 これは、 追跡する~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^I は,~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.
10.10. 同期c~mapper関数から作成される形式変換~stream
次の関数は、 通常は `Array.prototype.map$c に渡すような型の同期的な “~mapper” 関数から, 新たな `TransformStream$I ~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$I を作成できる: ◎ 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^jE を重ねて~logする:
◎
Logs a SyntaxError, twice:
*/
%reader.read().catch(%e => console.error(%e));
%writer.write(`{}^l).catch(%e => console.error(%e));
10.11. 恒等変換~streamを新たな可読~streamを作成する~primitiveとして利用する
`恒等変換~stream$を `pipeTo()$rs と組合せれば,~streamを操作する強力な仕方になる。 この節では、 この一般~技法の例を二三与える。 ◎ Combining an identity transform stream with pipeTo() is a powerful way to manipulate streams. This section contains a couple of examples of this general technique.
ときには、 `可読~stream$用の~promiseを可読~streamであったかのように扱うと自然になる。 必要なものは、 単純な~adapter関数の他にない: ◎ It’s sometimes natural to treat a promise for a readable stream as if it were a readable stream. A simple adapter function is all that’s needed:
function promiseToReadable(%promiseForReadable) { const %ts = new TransformStream(); %promiseForReadable .then(%readable => %readable.pipeTo(%ts.writable)) .catch(%reason => %ts.writable.abort(%reason)) .catch(() => {}); return %ts.readable; }
ここでは、 ~dataを`可書~側$へ~pipeして,`可読~側$を返す。 ~pipeが~errorした場合、 可書~側を`中止する$ — ~errorは、 返された可読~側へ自動的に伝播する。 `pipeTo()$rs までに,すでに可書~側が~errorしていた場合、 `abort()$ws ~callは却下を返すことになる — それは、 安全に無視できる。 ◎ Here, we pipe the data to the writable side and return the readable side. If the pipe errors, we abort the writable side, which automatically propagates the error to the returned readable side. If the writable side had already been errored by pipeTo(), then the abort() call will return a rejection, which we can safely ignore.
これのもっと複階的な拡張は、 複数の可読~streamを 1 つに連結することである: ◎ A more complex extension of this is concatenating multiple readable streams into one:
function concatenateReadables(%readables) { const %ts = new TransformStream(); let %promise = Promise.resolve(); for (const %readable of %readables) { %promise = %promise.then( () => %readable.pipeTo(%ts.writable, { preventClose: true }), %reason => { return Promise.all([ %ts.writable.abort(%reason), %readable.cancel(%reason) ]); } ); } %promise.then(() => %ts.writable.close(), %reason => %ts.writable.abort(%reason)) .catch(() => {}); return %ts.readable; }
ここでの~errorの取扱いは、 より巧妙になる — 連結した~streamを取消すには、 すべての入力~streamを取消す必要があるので。 しかしながら,成功~事例は十分~単純である。 可反復 %readables 内で各~streamを 1 個ずつ`恒等変換~stream$の`可書~側$へ~pipeして, 済んだら それを~closeするだけである。 `可読~側$は、[ 各~streamからの すべての~chunk ]すべての連結になる。 関数からは、 それを返す。 背圧は通例通りに適用される。 ◎ The error handling here is subtle because canceling the concatenated stream has to cancel all the input streams. However, the success case is simple enough. We just pipe each stream in the readables iterable one at a time to the identity transform stream's writable side, and then close it when we are done. The readable side is then a concatenation of all the chunks from all of of the streams. We return it from the function. Backpressure is applied as usual.
謝辞
次に挙げる方々のみならず、 この仕様に貢献された すべての方々に感謝する。 彼らなくしては、 この仕様は成し得なかったであろう:
`_acks1@