UNPKG

@johngw/stream

Version:

Reactive programming tools using the WHATWG Streams API.

67 lines (60 loc) 1.55 kB
/** * Options for {@link toIterator}. * * @group Sinks */ export interface ToIteratorOptions { signal: AbortSignal } /** * Turns a `ReadableStream` in to an `AsyncIterator`. * * @group Sinks * @see {@link toIterable:function} * @example * ``` * const iterator = toIterator(stream) * while (true) { * const result = await iterator.next() * if (result.done) break * doSomething(result.value) * } * ``` */ export function toIterator<T>( stream: ReadableStream<T>, options?: ToIteratorOptions ): AsyncIterator<T> { return new StreamIterator(stream, options?.signal) } class StreamIterator<T> implements AsyncIterator<T> { #reader: ReadableStreamDefaultReader<T> #signal?: AbortSignal constructor(stream: ReadableStream<T>, signal?: AbortSignal) { this.#reader = stream.getReader() this.#signal = signal if (signal?.aborted) this.throw(signal.reason) signal?.addEventListener('abort', () => this.throw(signal.reason)) } next() { return this.#signal?.aborted ? Promise.reject(this.#signal.reason) : (this.#reader.read() as Promise<IteratorResult<T>>) } async return(value: T): Promise<IteratorResult<T>> { try { await this.#reader.cancel() } catch (error) { // potentially already closed } return { done: true, value } } async throw(reason?: unknown): Promise<IteratorResult<T>> { try { await this.#reader.cancel(reason) } catch (error) { // potentially already closed } return { done: true, value: undefined } } }