aboutsummaryrefslogtreecommitdiff
path: root/src/observable.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/observable.ts')
-rw-r--r--src/observable.ts16
1 files changed, 14 insertions, 2 deletions
diff --git a/src/observable.ts b/src/observable.ts
index 15a1a2e..5185c9f 100644
--- a/src/observable.ts
+++ b/src/observable.ts
@@ -5,6 +5,9 @@
*/
export class OVar<T> {
private _value: T
+ private weak = false; // if weak, the source will be unsubscribed from, if all listeners are removed
+ private disabled = false
+ private cancel_source?: () => void
private observers: ((v: T) => unknown)[] = []
constructor(initial: T) {
@@ -16,8 +19,16 @@ export class OVar<T> {
change() { this.observers.forEach(o => o(this._value)) }
onchange(handler: (v: T) => unknown): () => void {
+ if (this.disabled) throw new Error("obervable is disabled");
this.observers.push(handler)
- return () => this.observers = this.observers.filter(o => o != handler)
+ if (this.observers.length > 16) console.warn("likely memory leak here:", this);
+ return () => {
+ this.observers = this.observers.filter(o => o != handler)
+ if (this.observers.length == 0 && this.weak) {
+ this.cancel_source!()
+ this.disabled = true
+ }
+ }
}
onchangeinit(handler: (v: T) => unknown): () => void {
const abort = this.onchange(handler)
@@ -26,7 +37,8 @@ export class OVar<T> {
}
map<U>(fn: (v: T) => U): OVar<U> {
const uv = new OVar(fn(this.value))
- this.onchange(v => uv.value = fn(v))
+ uv.cancel_source = this.onchange(v => uv.value = fn(v))
+ uv.weak = true
return uv;
}
wait_for(val: T) {