UNPKG

@thi.ng/transducers-async

Version:

Async versions of various highly composable transducers, reducers and iterators

80 lines (79 loc) 1.93 kB
import { illegalState } from "@thi.ng/errors/illegal-state"; const mult = (src) => new Mult(src); class Mult { constructor(src) { this.src = src; } subs = []; isActive = false; /** * Creates a new subscription (aka custom `AsyncIterable`) which will * receive any future values from `src`. The returned subscription can be * removed again via {@link Mult.unsubscribe}. */ subscribe() { const sub = new MSub(); this.subs.push(sub); if (!this.isActive) { this.isActive = true; (async () => { for await (let val of this.src) { for (const s of this.subs) s.resolve(val); if (val === void 0) this.subs.length = 0; if (!this.subs.length) break; await Promise.all(this.subs.map((x) => x.notifyP)); } for (const s of this.subs) s.resolve(void 0); this.subs.length = 0; this.isActive = false; })(); } return sub; } /** * Attempts to remove given child subscription (presumably created via * {@link Mult.subscribe}). Returns true if removal was successful. * * @param sub */ unsubscribe(sub) { const idx = this.subs.findIndex((x) => x === sub); if (idx >= 0) { this.subs.splice(idx, 1); sub.resolve(void 0); return true; } return false; } } class MSub { valueP; notifyP; resolve; notify; active = false; constructor() { this.$await(); } async *[Symbol.asyncIterator]() { if (this.active) illegalState("multiple consumers unsupported"); this.active = true; while (true) { const res = await this.valueP; if (res === void 0) break; yield res; this.notify(); this.$await(); } this.active = false; } $await() { this.notifyP = new Promise((res) => this.notify = res); this.valueP = new Promise((res) => this.resolve = res); } } export { MSub, Mult, mult };