value-enhancer
Advanced tools
Comparing version 2.0.1 to 2.0.2
@@ -10,6 +10,4 @@ import { ReadonlyValImpl } from "./readonly-val"; | ||
private _sVal_; | ||
private _sOldValue_; | ||
private _transform_; | ||
private _dirty_; | ||
private _newValue_; | ||
private _dirtyLevel_; | ||
} | ||
@@ -16,0 +14,0 @@ export interface CreateCombine { |
@@ -8,5 +8,4 @@ import { ReadonlyValImpl } from "./readonly-val"; | ||
private _sVal_; | ||
private _sOldValue_; | ||
private _transform_; | ||
private _dirty_; | ||
private _dirtyLevel_; | ||
} | ||
@@ -13,0 +12,0 @@ export interface CreateDerive { |
@@ -16,4 +16,4 @@ import { Subscribers } from "./subscribers"; | ||
*/ | ||
_compute_(subscriber: ValSubscriber<TValue>): ValDisposer; | ||
_compute_(subscriber: ValSubscriber<void>): ValDisposer; | ||
unsubscribe(subscriber?: (...args: any[]) => any): void; | ||
} |
import type { ReadonlyVal, ValDisposer, ValSubscriber } from "./typings"; | ||
export declare type SubscriberMode = | ||
/** Async */ | ||
"s0" | ||
/** Eager */ | ||
| "s1" | ||
/** Computed */ | ||
| "s2"; | ||
declare type SubscriberMode = 1 | 2 | 3; | ||
export declare class Subscribers<TValue = any> { | ||
size_: number; | ||
constructor(val: ReadonlyVal<TValue>, initialValue: TValue, start?: (() => void | ValDisposer | undefined) | null); | ||
constructor(val: ReadonlyVal<TValue>, start?: (() => void | ValDisposer | undefined) | null); | ||
invoke_(): void; | ||
@@ -17,13 +10,13 @@ add_(subscriber: ValSubscriber, mode: SubscriberMode): () => void; | ||
exec_(mode: SubscriberMode): void; | ||
shouldExec_: boolean; | ||
readonly subscribers_: Map<ValSubscriber<TValue>, SubscriberMode>; | ||
private _stop_; | ||
private _val_; | ||
/** Async */ | ||
private s0?; | ||
/** Eager */ | ||
private s1?; | ||
/** Computed */ | ||
private s2?; | ||
private _oldValue_; | ||
private readonly _val_; | ||
private [1]; | ||
private [2]; | ||
private [3]; | ||
private readonly _notReadySubscribers_; | ||
private _start_?; | ||
private _startDisposer_?; | ||
} | ||
export {}; |
@@ -5,1 +5,2 @@ import type { ReadonlyVal, TValInputsValueTuple } from "./typings"; | ||
export declare const dispose: (disposer: () => void) => void; | ||
export declare const INIT_VALUE: any; |
@@ -6,10 +6,5 @@ "use strict"; | ||
let pending; | ||
const schedule = (subs) => { | ||
subsSet.add(subs); | ||
pending = pending || nextTick.then(flush); | ||
}; | ||
const cancelTask = (subs) => subsSet.delete(subs); | ||
const flush = () => { | ||
for (const subs of subsSet) { | ||
subs.ex("s0"); | ||
subs.e(1); | ||
} | ||
@@ -19,55 +14,80 @@ pending = false; | ||
}; | ||
const sSize = (s) => s ? s.size : 0; | ||
const sDelete = (s, sub) => s && s.delete(sub) ? 1 : 0; | ||
const sClear = (s) => s && s.clear(); | ||
const schedule = (subs) => { | ||
subsSet.add(subs); | ||
pending = pending || nextTick.then(flush); | ||
}; | ||
const cancelTask = (subs) => subsSet.delete(subs); | ||
var _a, _b, _c; | ||
class Subscribers { | ||
constructor(val2, initialValue, start) { | ||
this.sz = 0; | ||
this.d = val2; | ||
this.b = initialValue; | ||
this.c = start; | ||
constructor(val2, start) { | ||
this.s = false; | ||
this.b = /* @__PURE__ */ new Map(); | ||
this[_a] = 0; | ||
this[_b] = 0; | ||
this[_c] = 0; | ||
this.d = /* @__PURE__ */ new Set(); | ||
this.h = val2; | ||
this.g = start; | ||
} | ||
iv() { | ||
this.ex("s2"); | ||
this.ex("s1"); | ||
if (sSize(this.s0)) { | ||
i() { | ||
if (this.d.size) { | ||
this.d.clear(); | ||
} | ||
this.e(3); | ||
this.e(2); | ||
if (this[1]) { | ||
schedule(this); | ||
} else { | ||
this.s = false; | ||
} | ||
} | ||
ad(subscriber, mode) { | ||
if (this.c && this.sz <= 0) { | ||
this.a = this.c(); | ||
a(subscriber, mode) { | ||
if (this.g && !this.b.size) { | ||
this.f = this.g(); | ||
} | ||
(this[mode] || (this[mode] = /* @__PURE__ */ new Set())).add(subscriber); | ||
this.sz += 1; | ||
return () => this.rm(subscriber); | ||
const currentMode = this.b.get(subscriber); | ||
if (currentMode) { | ||
this[currentMode]--; | ||
} | ||
this.d.add(subscriber); | ||
this.b.set(subscriber, mode); | ||
this[mode]++; | ||
return () => this.r(subscriber); | ||
} | ||
rm(subscriber) { | ||
this.sz -= sDelete(this.s0, subscriber) + sDelete(this.s1, subscriber) + sDelete(this.s2, subscriber); | ||
if (this.sz <= 0) { | ||
this.e(); | ||
r(subscriber) { | ||
const mode = this.b.get(subscriber); | ||
if (mode) { | ||
this.b.delete(subscriber); | ||
this[mode]--; | ||
if (this[1] + this[2] <= 0) { | ||
this.j(); | ||
} | ||
} | ||
} | ||
cl() { | ||
sClear(this.s0); | ||
sClear(this.s1); | ||
sClear(this.s2); | ||
this.sz = 0; | ||
c() { | ||
this.b.clear(); | ||
this.d.clear(); | ||
this[1] = this[2] = this[3] = 0; | ||
cancelTask(this); | ||
this.e(); | ||
this.j(); | ||
} | ||
ex(mode) { | ||
if (sSize(this[mode])) { | ||
const value = this.d.value; | ||
if (mode === "s0") { | ||
if (this.b === value) { | ||
e(mode) { | ||
if (this[mode]) { | ||
let value; | ||
if (mode !== 3) { | ||
value = this.h.value; | ||
} | ||
if (mode === 1) { | ||
if (!this.s) { | ||
return; | ||
} | ||
this.b = value; | ||
this.s = false; | ||
} | ||
for (const sub of this[mode]) { | ||
try { | ||
sub(value); | ||
} catch (e) { | ||
console.error(e); | ||
for (const [sub, subMode] of this.b) { | ||
if (subMode === mode && !this.d.has(sub)) { | ||
try { | ||
sub(value); | ||
} catch (e) { | ||
console.error(e); | ||
} | ||
} | ||
@@ -77,9 +97,7 @@ } | ||
} | ||
e() { | ||
if (this.a) { | ||
this.a(); | ||
this.a = null; | ||
} | ||
j() { | ||
this.f && (this.f = this.f()); | ||
} | ||
} | ||
_a = 1, _b = 2, _c = 3; | ||
class ReadonlyValImpl { | ||
@@ -91,4 +109,5 @@ _m(newValue, oldValue) { | ||
if (!this._m(value, this._v)) { | ||
this._u.s = true; | ||
this._v = value; | ||
this._u.iv(); | ||
this._u.i(); | ||
} | ||
@@ -101,3 +120,3 @@ } | ||
} | ||
this._u = new Subscribers(this, value, start); | ||
this._u = new Subscribers(this, start); | ||
} | ||
@@ -108,3 +127,3 @@ get value() { | ||
reaction(subscriber, eager) { | ||
return this._u.ad(subscriber, eager ? "s1" : "s0"); | ||
return this._u.a(subscriber, eager ? 2 : 1); | ||
} | ||
@@ -121,9 +140,9 @@ subscribe(subscriber, eager) { | ||
_c(subscriber) { | ||
return this._u.ad(subscriber, "s2"); | ||
return this._u.a(subscriber, 3); | ||
} | ||
unsubscribe(subscriber) { | ||
if (subscriber) { | ||
this._u.rm(subscriber); | ||
this._u.r(subscriber); | ||
} else { | ||
this._u.cl(); | ||
this._u.c(); | ||
} | ||
@@ -144,30 +163,32 @@ } | ||
} | ||
const identity = (value) => value; | ||
const getValue = (val2) => val2.value; | ||
const getValues = (valInputs) => valInputs.map(getValue); | ||
const dispose = (disposer) => disposer(); | ||
const INIT_VALUE = {}; | ||
class DerivedValImpl extends ReadonlyValImpl { | ||
constructor(val2, transform, config) { | ||
super( | ||
transform(val2.value), | ||
config, | ||
() => val2._c(() => { | ||
if (!this._d) { | ||
this._d = true; | ||
this._u.iv(); | ||
super(INIT_VALUE, config, () => { | ||
if (this._v === INIT_VALUE) { | ||
this._v = this._t(this._l.value); | ||
} else { | ||
this._d = this._d || 1; | ||
} | ||
return val2._c(() => { | ||
if (this._d < 2) { | ||
this._d = 2; | ||
this._u.i(); | ||
} | ||
}) | ||
); | ||
this._d = false; | ||
}); | ||
}); | ||
this._d = 0; | ||
this._l = val2; | ||
this._o = val2.value; | ||
this._t = transform; | ||
} | ||
get value() { | ||
if (this._d || this._u.sz <= 0) { | ||
this._d = false; | ||
const newValue = this._l.value; | ||
if (this._o !== newValue) { | ||
this._o = newValue; | ||
const value = this._t(newValue); | ||
if (!this._m(value, this._v)) { | ||
this._v = value; | ||
} | ||
} | ||
if (this._d || this._v === INIT_VALUE || !this._u.b.size) { | ||
const value = this._t(this._l.value); | ||
this._u.s = this._d > 0 && !this._m(value, this._v); | ||
this._v = value; | ||
this._d = 0; | ||
} | ||
@@ -177,15 +198,15 @@ return this._v; | ||
} | ||
const identity = (value) => value; | ||
const getValue = (val2) => val2.value; | ||
const getValues = (valInputs) => valInputs.map(getValue); | ||
const dispose = (disposer) => disposer(); | ||
class CombinedValImpl extends ReadonlyValImpl { | ||
constructor(valInputs, transform, config) { | ||
const sOldValues = getValues(valInputs); | ||
super(transform(sOldValues), config, () => { | ||
super(INIT_VALUE, config, () => { | ||
if (this._v === INIT_VALUE) { | ||
this._v = transform(getValues(this._l)); | ||
} else { | ||
this._d = this._d || 1; | ||
} | ||
const disposers = valInputs.map( | ||
(val2) => val2._c(() => { | ||
if (!this._d) { | ||
this._d = true; | ||
this._u.iv(); | ||
if (this._d < 2) { | ||
this._d = 2; | ||
this._u.i(); | ||
} | ||
@@ -196,27 +217,15 @@ }) | ||
}); | ||
this._d = false; | ||
this._d = 0; | ||
this._l = valInputs; | ||
this._o = sOldValues; | ||
this._t = transform; | ||
} | ||
get value() { | ||
if (this._d || this._u.sz <= 0) { | ||
this._d = false; | ||
const sNewValues = this._n(); | ||
if (sNewValues) { | ||
const value = this._t(sNewValues); | ||
if (!this._m(value, this._v)) { | ||
this._v = value; | ||
} | ||
} | ||
if (this._d || this._v === INIT_VALUE || !this._u.b.size) { | ||
const value = this._t(getValues(this._l)); | ||
this._u.s = this._d > 0 && !this._m(value, this._v); | ||
this._v = value; | ||
this._d = 0; | ||
} | ||
return this._v; | ||
} | ||
_n() { | ||
for (let i = 0; i < this._l.length; i++) { | ||
if (this._l[i].value !== this._o[i]) { | ||
return this._o = getValues(this._l); | ||
} | ||
} | ||
} | ||
} | ||
@@ -223,0 +232,0 @@ const val = (value, config) => new ValImpl(value, config); |
{ | ||
"name": "value-enhancer", | ||
"version": "2.0.1", | ||
"version": "2.0.2", | ||
"private": false, | ||
@@ -38,6 +38,7 @@ "description": "A tiny library to enhance value with reactive wrapper.", | ||
"types": "cross-env NODE_ENV=production tsc --declaration --emitDeclarationOnly --jsx react --esModuleInterop --outDir dist", | ||
"build": "vite build && npm run types", | ||
"build:dev": "vite build --mode development && npm run types", | ||
"build": "cross-env NODE_ENV=production vite build && npm run types", | ||
"build:min": "cross-env NODE_ENV=production MINIFY=true vite build && npm run types", | ||
"build:dev": "cross-env NODE_ENV=development vite build --mode development && npm run types", | ||
"release": "standard-version" | ||
} | ||
} |
@@ -20,4 +20,2 @@ # [value-enhancer](https://github.com/crimx/value-enhancer) | ||
[(v1)](https://github.com/crimx/value-enhancer/tree/v1) | ||
## Install | ||
@@ -35,2 +33,4 @@ | ||
It does not convert the value with `Object.defineProperty` nor `Proxy`. Keeping everything as plain JavaScript value makes it easier to work with other libraries and easier for the JavaScript engine to optimize. | ||
- Safe and fast. | ||
It solves multi-level derivation issue (exist in Svelte Stores) with smart lazy value evaluation. | ||
- Explicit. | ||
@@ -227,1 +227,5 @@ Reactive objects are easy to tell since their types are different from normal objects. Subscription also requires explicit dependency declaration which reduce the work of repetitive dynamic dependency collection in Proxy implementations. | ||
``` | ||
## Legacy | ||
[(v1)](https://github.com/crimx/value-enhancer/tree/v1) |
import { ReadonlyValImpl } from "./readonly-val"; | ||
import type { ReadonlyVal, TValInputsValueTuple, ValConfig } from "./typings"; | ||
import { dispose, getValues } from "./utils"; | ||
import { dispose, getValues, INIT_VALUE } from "./utils"; | ||
@@ -26,8 +26,12 @@ export type CombineValTransform< | ||
) { | ||
const sOldValues = getValues(valInputs); | ||
super(transform(sOldValues), config, () => { | ||
super(INIT_VALUE, config, () => { | ||
if (this._value_ === INIT_VALUE) { | ||
this._value_ = transform(getValues(this._sVal_)); | ||
} else { | ||
this._dirtyLevel_ = this._dirtyLevel_ || 1; | ||
} | ||
const disposers = valInputs.map(val => | ||
(val as ReadonlyValImpl)._compute_(() => { | ||
if (!this._dirty_) { | ||
this._dirty_ = true; | ||
if (this._dirtyLevel_ < 2) { | ||
this._dirtyLevel_ = 2; | ||
this._subs_.invoke_(); | ||
@@ -41,3 +45,2 @@ } | ||
this._sVal_ = valInputs; | ||
this._sOldValue_ = sOldValues; | ||
this._transform_ = transform; | ||
@@ -47,11 +50,12 @@ } | ||
public override get value(): TValue { | ||
if (this._dirty_ || this._subs_.size_ <= 0) { | ||
this._dirty_ = false; | ||
const sNewValues = this._newValue_(); | ||
if (sNewValues) { | ||
const value = this._transform_(sNewValues); | ||
if (!this._compare_(value, this._value_)) { | ||
this._value_ = value; | ||
} | ||
} | ||
if ( | ||
this._dirtyLevel_ || | ||
this._value_ === INIT_VALUE || | ||
!this._subs_.subscribers_.size | ||
) { | ||
const value = this._transform_(getValues(this._sVal_)); | ||
this._subs_.shouldExec_ = | ||
this._dirtyLevel_ > 0 && !this._compare_(value, this._value_); | ||
this._value_ = value; | ||
this._dirtyLevel_ = 0; | ||
} | ||
@@ -62,3 +66,2 @@ return this._value_; | ||
private _sVal_: TValInputs; | ||
private _sOldValue_: [...TValInputsValueTuple<TValInputs>]; | ||
private _transform_: CombineValTransform< | ||
@@ -68,11 +71,3 @@ TValue, | ||
>; | ||
private _dirty_ = false; | ||
private _newValue_(): [...TValInputsValueTuple<TValInputs>] | undefined { | ||
for (let i = 0; i < this._sVal_.length; i++) { | ||
if (this._sVal_[i].value !== this._sOldValue_[i]) { | ||
return (this._sOldValue_ = getValues(this._sVal_)); | ||
} | ||
} | ||
} | ||
private _dirtyLevel_ = 0; | ||
} | ||
@@ -79,0 +74,0 @@ |
import { ReadonlyValImpl } from "./readonly-val"; | ||
import type { ReadonlyVal, ValConfig } from "./typings"; | ||
import { INIT_VALUE } from "./utils"; | ||
@@ -17,13 +18,17 @@ export type DeriveValTransform<TValue = any, TDerivedValue = any> = ( | ||
) { | ||
super(transform(val.value), config, () => | ||
(val as ReadonlyValImpl)._compute_(() => { | ||
if (!this._dirty_) { | ||
this._dirty_ = true; | ||
super(INIT_VALUE, config, () => { | ||
if (this._value_ === INIT_VALUE) { | ||
this._value_ = this._transform_(this._sVal_.value); | ||
} else { | ||
this._dirtyLevel_ = this._dirtyLevel_ || 1; | ||
} | ||
return (val as ReadonlyValImpl)._compute_(() => { | ||
if (this._dirtyLevel_ < 2) { | ||
this._dirtyLevel_ = 2; | ||
this._subs_.invoke_(); | ||
} | ||
}) | ||
); | ||
}); | ||
}); | ||
this._sVal_ = val; | ||
this._sOldValue_ = val.value; | ||
this._transform_ = transform; | ||
@@ -33,12 +38,12 @@ } | ||
public override get value(): TValue { | ||
if (this._dirty_ || this._subs_.size_ <= 0) { | ||
this._dirty_ = false; | ||
const newValue = this._sVal_.value; | ||
if (this._sOldValue_ !== newValue) { | ||
this._sOldValue_ = newValue; | ||
const value = this._transform_(newValue); | ||
if (!this._compare_(value, this._value_)) { | ||
this._value_ = value; | ||
} | ||
} | ||
if ( | ||
this._dirtyLevel_ || | ||
this._value_ === INIT_VALUE || | ||
!this._subs_.subscribers_.size | ||
) { | ||
const value = this._transform_(this._sVal_.value); | ||
this._subs_.shouldExec_ = | ||
this._dirtyLevel_ > 0 && !this._compare_(value, this._value_); | ||
this._value_ = value; | ||
this._dirtyLevel_ = 0; | ||
} | ||
@@ -49,6 +54,4 @@ return this._value_; | ||
private _sVal_: ReadonlyVal<TSrcValue>; | ||
private _sOldValue_: TSrcValue; | ||
private _transform_: DeriveValTransform<TSrcValue, TValue>; | ||
private _dirty_ = false; | ||
private _dirtyLevel_ = 0; | ||
} | ||
@@ -55,0 +58,0 @@ |
@@ -21,2 +21,3 @@ import { Subscribers } from "./subscribers"; | ||
if (!this._compare_(value, this._value_)) { | ||
this._subs_.shouldExec_ = true; | ||
this._value_ = value; | ||
@@ -38,3 +39,3 @@ this._subs_.invoke_(); | ||
this._subs_ = new Subscribers<TValue>(this, value, start); | ||
this._subs_ = new Subscribers<TValue>(this, start); | ||
} | ||
@@ -50,3 +51,3 @@ | ||
): ValDisposer { | ||
return this._subs_.add_(subscriber, eager ? "s1" : "s0"); | ||
return this._subs_.add_(subscriber, eager ? 2 /* Eager */ : 1 /* Async */); | ||
} | ||
@@ -71,4 +72,4 @@ | ||
*/ | ||
public _compute_(subscriber: ValSubscriber<TValue>): ValDisposer { | ||
return this._subs_.add_(subscriber, "s2"); | ||
public _compute_(subscriber: ValSubscriber<void>): ValDisposer { | ||
return this._subs_.add_(subscriber, 3 /* Computed */); | ||
} | ||
@@ -75,0 +76,0 @@ |
@@ -9,2 +9,10 @@ import type { Subscribers } from "./subscribers"; | ||
const flush = () => { | ||
for (const subs of subsSet) { | ||
subs.exec_(1 /* Async */); | ||
} | ||
pending = false; | ||
subsSet.clear(); | ||
}; | ||
export const schedule = <TValue>(subs: Subscribers<TValue>): void => { | ||
@@ -16,9 +24,1 @@ subsSet.add(subs); | ||
export const cancelTask = (subs: Subscribers): boolean => subsSet.delete(subs); | ||
const flush = () => { | ||
for (const subs of subsSet) { | ||
subs.exec_("s0"); | ||
} | ||
pending = false; | ||
subsSet.clear(); | ||
}; |
import { cancelTask, schedule } from "./scheduler"; | ||
import type { ReadonlyVal, ValDisposer, ValSubscriber } from "./typings"; | ||
const sSize = (s: Set<ValSubscriber> | undefined): number => (s ? s.size : 0); | ||
const sDelete = ( | ||
s: Set<ValSubscriber> | undefined, | ||
sub: ValSubscriber | ||
): 0 | 1 => (s && s.delete(sub) ? 1 : 0); | ||
const sClear = (s: Set<ValSubscriber> | undefined): unknown => s && s.clear(); | ||
type SubscriberMode = 1 /* Async */ | 2 /* Eager */ | 3; /* Computed */ | ||
export type SubscriberMode = | ||
/** Async */ | ||
| "s0" | ||
/** Eager */ | ||
| "s1" | ||
/** Computed */ | ||
| "s2"; | ||
export class Subscribers<TValue = any> { | ||
public size_ = 0; | ||
public constructor( | ||
val: ReadonlyVal<TValue>, | ||
initialValue: TValue, | ||
start?: (() => void | ValDisposer | undefined) | null | ||
) { | ||
this._val_ = val; | ||
this._oldValue_ = initialValue; | ||
this._start_ = start; | ||
@@ -33,6 +16,11 @@ } | ||
public invoke_(): void { | ||
this.exec_("s2"); | ||
this.exec_("s1"); | ||
if (sSize(this.s0)) { | ||
if (this._notReadySubscribers_.size) { | ||
this._notReadySubscribers_.clear(); | ||
} | ||
this.exec_(3 /* Computed */); | ||
this.exec_(2 /* Eager */); | ||
if (this[1 /* Async */]) { | ||
schedule(this); | ||
} else { | ||
this.shouldExec_ = false; | ||
} | ||
@@ -42,10 +30,14 @@ } | ||
public add_(subscriber: ValSubscriber, mode: SubscriberMode): () => void { | ||
if (this._start_ && this.size_ <= 0) { | ||
if (this._start_ && !this.subscribers_.size) { | ||
this._startDisposer_ = this._start_(); | ||
} | ||
(this[mode] || (this[mode] = new Set())).add(subscriber); | ||
const currentMode = this.subscribers_.get(subscriber); | ||
if (currentMode) { | ||
this[currentMode]--; | ||
} | ||
this._notReadySubscribers_.add(subscriber); | ||
this.subscribers_.set(subscriber, mode); | ||
this[mode]++; | ||
this.size_ += 1; | ||
return (): void => this.remove_(subscriber); | ||
@@ -55,8 +47,9 @@ } | ||
public remove_(subscriber: ValSubscriber): void { | ||
this.size_ -= | ||
sDelete(this.s0, subscriber) + | ||
sDelete(this.s1, subscriber) + | ||
sDelete(this.s2, subscriber); | ||
if (this.size_ <= 0) { | ||
this._stop_(); | ||
const mode = this.subscribers_.get(subscriber); | ||
if (mode) { | ||
this.subscribers_.delete(subscriber); | ||
this[mode]--; | ||
if (this[1 /* Async */] + this[2 /* Eager */] <= 0) { | ||
this._stop_(); | ||
} | ||
} | ||
@@ -66,6 +59,5 @@ } | ||
public clear_(): void { | ||
sClear(this.s0); | ||
sClear(this.s1); | ||
sClear(this.s2); | ||
this.size_ = 0; | ||
this.subscribers_.clear(); | ||
this._notReadySubscribers_.clear(); | ||
this[1 /* Async */] = this[2 /* Eager */] = this[3 /* Computed */] = 0; | ||
cancelTask(this); | ||
@@ -76,15 +68,20 @@ this._stop_(); | ||
public exec_(mode: SubscriberMode): void { | ||
if (sSize(this[mode])) { | ||
const value = this._val_.value; | ||
if (mode === "s0") { | ||
if (this._oldValue_ === value) { | ||
if (this[mode]) { | ||
let value: TValue | undefined; | ||
if (mode !== 3 /* Computed */) { | ||
value = this._val_.value; | ||
} | ||
if (mode === 1 /* Async */) { | ||
if (!this.shouldExec_) { | ||
return; | ||
} | ||
this._oldValue_ = value; | ||
this.shouldExec_ = false; | ||
} | ||
for (const sub of this[mode]!) { | ||
try { | ||
sub(value); | ||
} catch (e) { | ||
console.error(e); | ||
for (const [sub, subMode] of this.subscribers_) { | ||
if (subMode === mode && !this._notReadySubscribers_.has(sub)) { | ||
try { | ||
sub(value as TValue); | ||
} catch (e) { | ||
console.error(e); | ||
} | ||
} | ||
@@ -95,19 +92,20 @@ } | ||
public shouldExec_ = false; | ||
public readonly subscribers_ = new Map< | ||
ValSubscriber<TValue>, | ||
SubscriberMode | ||
>(); | ||
private _stop_(): void { | ||
if (this._startDisposer_) { | ||
this._startDisposer_(); | ||
this._startDisposer_ = null; | ||
} | ||
this._startDisposer_ && (this._startDisposer_ = this._startDisposer_()); | ||
} | ||
private _val_: ReadonlyVal<TValue>; | ||
private readonly _val_: ReadonlyVal<TValue>; | ||
/** Async */ | ||
private s0?: Set<ValSubscriber<TValue>>; | ||
/** Eager */ | ||
private s1?: Set<ValSubscriber<TValue>>; | ||
/** Computed */ | ||
private s2?: Set<ValSubscriber<TValue>>; | ||
private [1 /* Async */] = 0; | ||
private [2 /* Eager */] = 0; | ||
private [3 /* Computed */] = 0; | ||
private _oldValue_: TValue; | ||
private readonly _notReadySubscribers_ = new Set<ValSubscriber<TValue>>(); | ||
@@ -114,0 +112,0 @@ private _start_?: (() => void | ValDisposer | undefined) | null; |
@@ -13,1 +13,3 @@ import type { ReadonlyVal, TValInputsValueTuple } from "./typings"; | ||
export const dispose = (disposer: () => void): void => disposer(); | ||
export const INIT_VALUE: any = {}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
93414
1225
229