@benev/slate
Version:
frontend web stuff
78 lines • 2.6 kB
JavaScript
import { Op } from "../op/op.js";
import { ob } from "../tools/ob.js";
import { Signal } from "./signal.js";
import { OpSignal } from "./op_signal.js";
import { SignalTracker } from "./parts/tracker.js";
export class SignalTower {
// TODO wrap all signals in WeakRef, to promote garbage collection?
#signals = new Set();
#waiters = new Set();
signal(value) {
const signal = new Signal(value);
this.#signals.add(signal);
return signal;
}
computed(fun) {
const signal = this.signal(fun());
this.reaction(() => { signal.value = fun(); });
return signal;
}
async computedAsync(collector, responder) {
const value = await responder(collector());
const signal = this.signal(value);
this.reaction(collector, async (x) => {
signal.value = await responder(x);
});
return signal;
}
op(op = Op.loading()) {
const signal = new OpSignal(op);
this.#signals.add(signal);
return signal;
}
load(fn) {
const signal = this.op(Op.loading());
signal.load(fn);
return signal;
}
many(states) {
return (ob(states).map(state => this.signal(state)));
}
reaction(collector, responder) {
const tracker = new SignalTracker({
waiters: this.#waiters,
all_signals: this.#signals,
});
const track = { collector, responder };
const { recording } = tracker.observe(track.collector);
tracker.add_listeners(track, recording);
return () => tracker.shutdown();
}
lean(actor) {
const tracker = new SignalTracker({
waiters: this.#waiters,
all_signals: this.#signals,
});
const track = { lean: true, actor };
return {
stop: () => tracker.shutdown(),
collect: collector => {
const { payload, recording } = tracker.observe(collector);
tracker.add_listeners(track, recording);
return payload;
},
};
}
// TODO this is a hack, we shouldn't have to wait two cycles to be sure everything's done
async #waitOneCycle() {
return await Promise.all([...this.#signals].map(s => s.wait))
.then(() => Promise.all([...this.#waiters]))
.then(() => { this.#waiters.clear(); });
}
get wait() {
return Promise.resolve()
.then(() => this.#waitOneCycle())
.then(() => this.#waitOneCycle());
}
}
//# sourceMappingURL=tower.js.map