@thi.ng/transducers-async
Version:
Async versions of various highly composable transducers, reducers and iterators
84 lines (83 loc) • 2.19 kB
JavaScript
import { MSub } from "./mult.js";
const pubsub = (src, topicFn) => new PubSub(src, topicFn);
class PubSub {
constructor(src, topicFn) {
this.src = src;
this.topicFn = topicFn;
}
topics = /* @__PURE__ */ new Map();
isActive = false;
/**
* Creates a new subscription (aka custom `AsyncIterable`) which will
* receive any future values from `src` matching given topic `id`. The
* returned subscription can be removed again via
* {@link PubSub.unsubscribeTopic}.
*/
subscribeTopic(id) {
const sub = new MSub();
let subs = this.topics.get(id);
if (!subs) {
this.topics.set(id, subs = []);
}
subs.push(sub);
if (!this.isActive) {
this.isActive = true;
this.process();
}
return sub;
}
/**
* Similar to {@link PubSub.subscribeTopic}, but for one-off event handling.
* Creates a new subscription for topic `id` and waits for next value. Once
* received, it immediately unsubscribes again and then calls `fn` with
* value.
*
* @param id
* @param fn
*/
subscribeOnce(id, fn) {
const sub = this.subscribeTopic(id);
const $this = this;
(async () => {
for await (let x of sub) {
$this.unsubscribeTopic(id, sub);
fn(x);
}
})();
}
/**
* Attempts to remove given child subscription (presumably created via
* {@link PubSub.subscribeTopic}). Returns true if removal was successful.
*
* @param sub
*/
unsubscribeTopic(id, sub) {
const subs = this.topics.get(id);
if (!subs) return false;
const idx = subs.findIndex((x) => x === sub);
if (idx >= 0) {
subs.splice(idx, 1);
sub.resolve(void 0);
return true;
}
return false;
}
async process() {
for await (let val of this.src) {
const topic = this.topicFn(val);
const subs = this.topics.get(topic);
if (!subs?.length) continue;
for (let s of subs) s.resolve(val);
await Promise.all(subs.map((x) => x.notifyP));
}
for (let subs of this.topics.values()) {
for (let s of subs) s.resolve(void 0);
}
this.topics.clear();
this.isActive = false;
}
}
export {
PubSub,
pubsub
};