From a7141ec5b9afe4343273d8d3c075744b2c9f6d91 Mon Sep 17 00:00:00 2001 From: Dor Shtaif Date: Fri, 29 Sep 2023 16:10:54 +0300 Subject: [PATCH] docs: edit and add some more JSDocs (#46) edit some JSDocs and add new ones for the `iterified` function and the `ExecutorFn` type --- src/iterified.ts | 66 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/src/iterified.ts b/src/iterified.ts index 0eb334e..593c9fb 100644 --- a/src/iterified.ts +++ b/src/iterified.ts @@ -10,13 +10,58 @@ export { type IterifiedIterator, }; -function iterified(executorFn: ExecutorFn): IterifiedIterable { - let channel = createMulticastChannel(); +/** + * Creates an `iterified` async iterable, yielding each value as it gets emitted from the user-provided `executorFn`. + * + * The given _executor function_ will be _"lazily"_ executed only upon pulling the first value from any iterator (or [`for await...of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of) loop) of the `iterified` iterable. Any additional iterators obtained from that point on would all feed off of the same shared execution of the _executor function_ - every value it yields will be distributed ("multicast") down to each active iterator, picking up from the time it was obtained. When the iterable is ended either by the producer (_executor function_ calls `done()` or `error(e)`) or the consumer (last active iterator is closed) - it would trigger an optionally-given teardown function before finally closing off the `iterified` iterable. This life cycle __repeats__ from the begining every time the `iterified` iterable gets reconsumed again. + * + * @param executorFn - a user-provided _executor function_ (see {@link ExecutorFn}) that controls the values to emit through the `iterified` iterable, closing it or erroring out, and provides logic for teardown. + * + * @returns an `iterified` async iterable + * + * @see {@link ExecutorFn}, {@link IterifiedIterable} + * + * @example + ```ts + import { iterified } from 'iterified'; + + // Iterable that emits "my_value" and ends immediately: + const iterable = iterified((next, done, error) => { + next('my_value'); + done(); + }); + ``` + * + * @example + ```ts + import { iterified } from 'iterified'; + + function webSocketIterable(url: string) { + return iterified((next, done, error) => { + const ws = new WebSocket(url); + + ws.addEventListener('close', ev => done()); + ws.addEventListener('error', ev => error(ev)); + ws.addEventListener('message', ev => next(ev.data)); + + return () => ws.close(); // <-- Ensures the web socket will properly close on any event our iterable gets disposed + }); + } + + (async () => { + for await (const msg of webSocketIterable('ws://localhost:8080')) { + console.log(msg); + } + })(); + ``` + */ +function iterified(executorFn: ExecutorFn): IterifiedIterable { + let channel = createMulticastChannel(); let activeIteratorCount = 0; - let executorPossiblyReturnedTeardown: ReturnType>; + let executorPossiblyReturnedTeardown: ReturnType>; let teardownInProgressPromise: Promise | undefined; - function executorPushCb(nextValue: TNext): void { + function executorPushCb(nextValue: T): void { if (!teardownInProgressPromise) { channel.put(nextValue); } @@ -129,6 +174,19 @@ type IterifiedIterator = { return(): Promise>; }; +/** + * A function that expresses the values to emit through an `iterified` iterable and encapsulates any logic and resource management that should be involved in generating them. + * + * The _executor function_ is invoked with the following arguments: + * + * - `next(value)` - makes the iterable yield `value` to all consuming iterators + * - `done()` - makes the iterable end, closing all consuming iterators + * - `error(e)` - makes the iterable error out with given `e` and end, propagating the error to every consuming iterator + * + * In addition, the _executor function_ may __optionally__ return a teardown function for disposing of any state and open resources that have been used during execution. + * + * @see {@link TeardownFn} + */ type ExecutorFn = ( next: (nextValue: TNext) => void, done: () => void,