From 003d3cace44fa19cf4570879a6515462bb0bfe0d Mon Sep 17 00:00:00 2001 From: daishi Date: Tue, 17 Dec 2024 08:57:33 +0900 Subject: [PATCH 1/5] rename pending to batch --- src/vanilla/store.ts | 169 ++++++++++++++++++++----------------------- 1 file changed, 80 insertions(+), 89 deletions(-) diff --git a/src/vanilla/store.ts b/src/vanilla/store.ts index d5010a8ccf..8ba4b5b6af 100644 --- a/src/vanilla/store.ts +++ b/src/vanilla/store.ts @@ -77,7 +77,7 @@ type Mounted = { /** Set of mounted atoms that depends on the atom. */ readonly t: Set /** Function to run when the atom is unmounted. */ - u?: (pending: Pending) => void + u?: (batch: Batch) => void } /** @@ -138,7 +138,7 @@ const addPendingPromiseToDependency = ( } const addDependency = ( - pending: Pending | undefined, + batch: Batch | undefined, atom: Atom, atomState: AtomState, a: AnyAtom, @@ -152,53 +152,44 @@ const addDependency = ( addPendingPromiseToDependency(atom, atomState.v, aState) } aState.m?.t.add(atom) - if (pending) { - addPendingDependent(pending, a, atom) + if (batch) { + addBatchDependent(batch, a, atom) } } // -// Pending +// Batch // -type Pending = readonly [ +type Batch = readonly [ dependents: Map>, atomStates: Map, functions: Set<() => void>, ] -const createPending = (): Pending => [new Map(), new Map(), new Set()] +const createBatch = (): Batch => [new Map(), new Map(), new Set()] -const addPendingAtom = ( - pending: Pending, - atom: AnyAtom, - atomState: AtomState, -) => { - if (!pending[0].has(atom)) { - pending[0].set(atom, new Set()) +const addBatchAtom = (batch: Batch, atom: AnyAtom, atomState: AtomState) => { + if (!batch[0].has(atom)) { + batch[0].set(atom, new Set()) } - pending[1].set(atom, atomState) + batch[1].set(atom, atomState) } -const addPendingDependent = ( - pending: Pending, - atom: AnyAtom, - dependent: AnyAtom, -) => { - const dependents = pending[0].get(atom) +const addBatchDependent = (batch: Batch, atom: AnyAtom, dependent: AnyAtom) => { + const dependents = batch[0].get(atom) if (dependents) { dependents.add(dependent) } } -const getPendingDependents = (pending: Pending, atom: AnyAtom) => - pending[0].get(atom) +const getBatchDependents = (batch: Batch, atom: AnyAtom) => batch[0].get(atom) -const addPendingFunction = (pending: Pending, fn: () => void) => { - pending[2].add(fn) +const addBatchFunction = (batch: Batch, fn: () => void) => { + batch[2].add(fn) } -const flushPending = (pending: Pending) => { +const flushBatch = (batch: Batch) => { let error: AnyError let hasError = false const call = (fn: () => void) => { @@ -211,12 +202,12 @@ const flushPending = (pending: Pending) => { } } } - while (pending[1].size || pending[2].size) { - pending[0].clear() - const atomStates = new Set(pending[1].values()) - pending[1].clear() - const functions = new Set(pending[2]) - pending[2].clear() + while (batch[1].size || batch[2].size) { + batch[0].clear() + const atomStates = new Set(batch[1].values()) + batch[1].clear() + const functions = new Set(batch[2]) + batch[2].clear() atomStates.forEach((atomState) => atomState.m?.l.forEach(call)) functions.forEach(call) } @@ -304,7 +295,7 @@ const buildStore = ( } const readAtomState = ( - pending: Pending | undefined, + batch: Batch | undefined, atom: Atom, dirtyAtoms?: Set, ): AtomState => { @@ -324,7 +315,7 @@ const buildStore = ( ([a, n]) => // Recursively, read the atom state of the dependency, and // check if the atom epoch number is unchanged - readAtomState(pending, a, dirtyAtoms).n === n, + readAtomState(batch, a, dirtyAtoms).n === n, ) ) { return atomState @@ -347,17 +338,17 @@ const buildStore = ( return returnAtomValue(aState) } // a !== atom - const aState = readAtomState(pending, a, dirtyAtoms) + const aState = readAtomState(batch, a, dirtyAtoms) try { return returnAtomValue(aState) } finally { if (isSync) { - addDependency(pending, atom, atomState, a, aState) + addDependency(batch, atom, atomState, a, aState) } else { - const pending = createPending() - addDependency(pending, atom, atomState, a, aState) - mountDependencies(pending, atom, atomState) - flushPending(pending) + const batch = createBatch() + addDependency(batch, atom, atomState, a, aState) + mountDependencies(batch, atom, atomState) + flushBatch(batch) } } } @@ -397,9 +388,9 @@ const buildStore = ( valueOrPromise.onCancel?.(() => controller?.abort()) const complete = () => { if (atomState.m) { - const pending = createPending() - mountDependencies(pending, atom, atomState) - flushPending(pending) + const batch = createBatch() + mountDependencies(batch, atom, atomState) + flushBatch(batch) } } valueOrPromise.then(complete, complete) @@ -418,8 +409,8 @@ const buildStore = ( const readAtom = (atom: Atom): Value => returnAtomValue(readAtomState(undefined, atom)) - const getMountedOrPendingDependents = ( - pending: Pending, + const getMountedOrBatchDependents = ( + batch: Batch, atom: Atom, atomState: AtomState, ): Map => { @@ -436,7 +427,7 @@ const buildStore = ( getAtomState(atomWithPendingPromise), ) } - getPendingDependents(pending, atom)?.forEach((dependent) => { + getBatchDependents(batch, atom)?.forEach((dependent) => { dependents.set(dependent, getAtomState(dependent)) }) return dependents @@ -446,7 +437,7 @@ const buildStore = ( // what's described here for simplicity and performance reasons: // https://en.wikipedia.org/wiki/Topological_sorting#Depth-first_search function getSortedDependents( - pending: Pending, + batch: Batch, rootAtom: AnyAtom, rootAtomState: AtomState, ): [[AnyAtom, AtomState, number][], Set] { @@ -476,7 +467,7 @@ const buildStore = ( } visiting.add(a) // Push unvisited dependents onto the stack - for (const [d, s] of getMountedOrPendingDependents(pending, a, aState)) { + for (const [d, s] of getMountedOrBatchDependents(batch, a, aState)) { if (a !== d && !visiting.has(d)) { stack.push([d, s]) } @@ -486,14 +477,14 @@ const buildStore = ( } const recomputeDependents = ( - pending: Pending, + batch: Batch, atom: Atom, atomState: AtomState, ) => { // Step 1: traverse the dependency graph to build the topsorted atom list // We don't bother to check for cycles, which simplifies the algorithm. const [topsortedAtoms, markedAtoms] = getSortedDependents( - pending, + batch, atom, atomState, ) @@ -511,10 +502,10 @@ const buildStore = ( } } if (hasChangedDeps) { - readAtomState(pending, a, markedAtoms) - mountDependencies(pending, a, aState) + readAtomState(batch, a, markedAtoms) + mountDependencies(batch, a, aState) if (prevEpochNumber !== aState.n) { - addPendingAtom(pending, a, aState) + addBatchAtom(batch, a, aState) changedAtoms.add(a) } } @@ -523,13 +514,13 @@ const buildStore = ( } const writeAtomState = ( - pending: Pending, + batch: Batch, atom: WritableAtom, ...args: Args ): Result => { let isSync = true const getter: Getter = (a: Atom) => - returnAtomValue(readAtomState(pending, a)) + returnAtomValue(readAtomState(batch, a)) const setter: Setter = ( a: WritableAtom, ...args: As @@ -544,18 +535,18 @@ const buildStore = ( const prevEpochNumber = aState.n const v = args[0] as V setAtomStateValueOrPromise(a, aState, v) - mountDependencies(pending, a, aState) + mountDependencies(batch, a, aState) if (prevEpochNumber !== aState.n) { - addPendingAtom(pending, a, aState) - recomputeDependents(pending, a, aState) + addBatchAtom(batch, a, aState) + recomputeDependents(batch, a, aState) } return undefined as R } else { - return writeAtomState(pending, a, ...args) + return writeAtomState(batch, a, ...args) } } finally { if (!isSync) { - flushPending(pending) + flushBatch(batch) } } } @@ -570,23 +561,23 @@ const buildStore = ( atom: WritableAtom, ...args: Args ): Result => { - const pending = createPending() + const batch = createBatch() try { - return writeAtomState(pending, atom, ...args) + return writeAtomState(batch, atom, ...args) } finally { - flushPending(pending) + flushBatch(batch) } } const mountDependencies = ( - pending: Pending, + batch: Batch, atom: AnyAtom, atomState: AtomState, ) => { if (atomState.m && !isPendingPromise(atomState.v)) { for (const a of atomState.d.keys()) { if (!atomState.m.d.has(a)) { - const aMounted = mountAtom(pending, a, getAtomState(a)) + const aMounted = mountAtom(batch, a, getAtomState(a)) aMounted.t.add(atom) atomState.m.d.add(a) } @@ -594,7 +585,7 @@ const buildStore = ( for (const a of atomState.m.d || []) { if (!atomState.d.has(a)) { atomState.m.d.delete(a) - const aMounted = unmountAtom(pending, a, getAtomState(a)) + const aMounted = unmountAtom(batch, a, getAtomState(a)) aMounted?.t.delete(atom) } } @@ -602,16 +593,16 @@ const buildStore = ( } const mountAtom = ( - pending: Pending, + batch: Batch, atom: Atom, atomState: AtomState, ): Mounted => { if (!atomState.m) { // recompute atom state - readAtomState(pending, atom) + readAtomState(batch, atom) // mount dependencies first for (const a of atomState.d.keys()) { - const aMounted = mountAtom(pending, a, getAtomState(a)) + const aMounted = mountAtom(batch, a, getAtomState(a)) aMounted.t.add(atom) } // mount self @@ -626,14 +617,14 @@ const buildStore = ( if (isActuallyWritableAtom(atom)) { const mounted = atomState.m let setAtom: (...args: unknown[]) => unknown - const createInvocationContext = (pending: Pending, fn: () => T) => { + const createInvocationContext = (batch: Batch, fn: () => T) => { let isSync = true setAtom = (...args: unknown[]) => { try { - return writeAtomState(pending, atom, ...args) + return writeAtomState(batch, atom, ...args) } finally { if (!isSync) { - flushPending(pending) + flushBatch(batch) } } } @@ -643,12 +634,12 @@ const buildStore = ( isSync = false } } - addPendingFunction(pending, () => { - const onUnmount = createInvocationContext(pending, () => + addBatchFunction(batch, () => { + const onUnmount = createInvocationContext(batch, () => atomOnMount(atom, (...args) => setAtom(...args)), ) if (onUnmount) { - mounted.u = (pending) => createInvocationContext(pending, onUnmount) + mounted.u = (batch) => createInvocationContext(batch, onUnmount) } }) } @@ -657,7 +648,7 @@ const buildStore = ( } const unmountAtom = ( - pending: Pending, + batch: Batch, atom: Atom, atomState: AtomState, ): Mounted | undefined => { @@ -669,7 +660,7 @@ const buildStore = ( // unmount self const onUnmount = atomState.m.u if (onUnmount) { - addPendingFunction(pending, () => onUnmount(pending)) + addBatchFunction(batch, () => onUnmount(batch)) } delete atomState.m if (import.meta.env?.MODE !== 'production') { @@ -677,7 +668,7 @@ const buildStore = ( } // unmount dependencies for (const a of atomState.d.keys()) { - const aMounted = unmountAtom(pending, a, getAtomState(a)) + const aMounted = unmountAtom(batch, a, getAtomState(a)) aMounted?.t.delete(atom) } return undefined @@ -686,17 +677,17 @@ const buildStore = ( } const subscribeAtom = (atom: AnyAtom, listener: () => void) => { - const pending = createPending() + const batch = createBatch() const atomState = getAtomState(atom) - const mounted = mountAtom(pending, atom, atomState) + const mounted = mountAtom(batch, atom, atomState) const listeners = mounted.l listeners.add(listener) - flushPending(pending) + flushBatch(batch) return () => { listeners.delete(listener) - const pending = createPending() - unmountAtom(pending, atom, atomState) - flushPending(pending) + const batch = createBatch() + unmountAtom(batch, atom, atomState) + flushBatch(batch) } } @@ -724,20 +715,20 @@ const buildStore = ( }), dev4_get_mounted_atoms: () => debugMountedAtoms, dev4_restore_atoms: (values) => { - const pending = createPending() + const batch = createBatch() for (const [atom, value] of values) { if (hasInitialValue(atom)) { const atomState = getAtomState(atom) const prevEpochNumber = atomState.n setAtomStateValueOrPromise(atom, atomState, value) - mountDependencies(pending, atom, atomState) + mountDependencies(batch, atom, atomState) if (prevEpochNumber !== atomState.n) { - addPendingAtom(pending, atom, atomState) - recomputeDependents(pending, atom, atomState) + addBatchAtom(batch, atom, atomState) + recomputeDependents(batch, atom, atomState) } } } - flushPending(pending) + flushBatch(batch) }, } Object.assign(store, devStore) From 04763bb6436554024615e945b68218718a4a9136 Mon Sep 17 00:00:00 2001 From: daishi Date: Tue, 17 Dec 2024 09:02:13 +0900 Subject: [PATCH 2/5] use object instead of array --- src/vanilla/store.ts | 47 ++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/vanilla/store.ts b/src/vanilla/store.ts index 8ba4b5b6af..2dce312e93 100644 --- a/src/vanilla/store.ts +++ b/src/vanilla/store.ts @@ -161,32 +161,41 @@ const addDependency = ( // Batch // -type Batch = readonly [ - dependents: Map>, - atomStates: Map, - functions: Set<() => void>, -] - -const createBatch = (): Batch => [new Map(), new Map(), new Set()] +const BATCH_DEPENDENTS = 'd' +const BATCH_ATOM_STATES = 'a' +const BATCH_FUNCTIONS = 'f' + +type Batch = Readonly<{ + [BATCH_DEPENDENTS]: Map> + [BATCH_ATOM_STATES]: Map + [BATCH_FUNCTIONS]: Set<() => void> +}> + +const createBatch = (): Batch => ({ + [BATCH_DEPENDENTS]: new Map(), + [BATCH_ATOM_STATES]: new Map(), + [BATCH_FUNCTIONS]: new Set(), +}) const addBatchAtom = (batch: Batch, atom: AnyAtom, atomState: AtomState) => { - if (!batch[0].has(atom)) { - batch[0].set(atom, new Set()) + if (!batch[BATCH_DEPENDENTS].has(atom)) { + batch[BATCH_DEPENDENTS].set(atom, new Set()) } - batch[1].set(atom, atomState) + batch[BATCH_ATOM_STATES].set(atom, atomState) } const addBatchDependent = (batch: Batch, atom: AnyAtom, dependent: AnyAtom) => { - const dependents = batch[0].get(atom) + const dependents = batch[BATCH_DEPENDENTS].get(atom) if (dependents) { dependents.add(dependent) } } -const getBatchDependents = (batch: Batch, atom: AnyAtom) => batch[0].get(atom) +const getBatchDependents = (batch: Batch, atom: AnyAtom) => + batch[BATCH_DEPENDENTS].get(atom) const addBatchFunction = (batch: Batch, fn: () => void) => { - batch[2].add(fn) + batch[BATCH_FUNCTIONS].add(fn) } const flushBatch = (batch: Batch) => { @@ -202,12 +211,12 @@ const flushBatch = (batch: Batch) => { } } } - while (batch[1].size || batch[2].size) { - batch[0].clear() - const atomStates = new Set(batch[1].values()) - batch[1].clear() - const functions = new Set(batch[2]) - batch[2].clear() + while (batch[BATCH_ATOM_STATES].size || batch[BATCH_FUNCTIONS].size) { + batch[BATCH_DEPENDENTS].clear() + const atomStates = new Set(batch[BATCH_ATOM_STATES].values()) + batch[BATCH_ATOM_STATES].clear() + const functions = new Set(batch[BATCH_FUNCTIONS]) + batch[BATCH_FUNCTIONS].clear() atomStates.forEach((atomState) => atomState.m?.l.forEach(call)) functions.forEach(call) } From adce1e4ad9c74661d4ec85186170b78c64d2d93e Mon Sep 17 00:00:00 2001 From: daishi Date: Tue, 17 Dec 2024 09:16:12 +0900 Subject: [PATCH 3/5] refactor with to function queues --- src/vanilla/store.ts | 72 ++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/src/vanilla/store.ts b/src/vanilla/store.ts index 2dce312e93..08958e5ce2 100644 --- a/src/vanilla/store.ts +++ b/src/vanilla/store.ts @@ -153,7 +153,7 @@ const addDependency = ( } aState.m?.t.add(atom) if (batch) { - addBatchDependent(batch, a, atom) + addBatchAtomDependent(batch, a, atom) } } @@ -161,41 +161,57 @@ const addDependency = ( // Batch // -const BATCH_DEPENDENTS = 'd' -const BATCH_ATOM_STATES = 'a' -const BATCH_FUNCTIONS = 'f' +const BATCH_ATOM_DEPENDENTS = 'd' +const BATCH_FUNC_MEDIUM = 'm' +const BATCH_FUNC_LOW = 'l' type Batch = Readonly<{ - [BATCH_DEPENDENTS]: Map> - [BATCH_ATOM_STATES]: Map - [BATCH_FUNCTIONS]: Set<() => void> + [BATCH_ATOM_DEPENDENTS]: Map> + [BATCH_FUNC_MEDIUM]: Set<() => void> + [BATCH_FUNC_LOW]: Set<() => void> }> const createBatch = (): Batch => ({ - [BATCH_DEPENDENTS]: new Map(), - [BATCH_ATOM_STATES]: new Map(), - [BATCH_FUNCTIONS]: new Set(), + [BATCH_ATOM_DEPENDENTS]: new Map(), + [BATCH_FUNC_MEDIUM]: new Set(), + [BATCH_FUNC_LOW]: new Set(), }) +const addBatchFuncMedium = (batch: Batch, fn: () => void) => { + batch[BATCH_FUNC_MEDIUM].add(fn) +} + +const addBatchFuncLow = (batch: Batch, fn: () => void) => { + batch[BATCH_FUNC_LOW].add(fn) +} + const addBatchAtom = (batch: Batch, atom: AnyAtom, atomState: AtomState) => { - if (!batch[BATCH_DEPENDENTS].has(atom)) { - batch[BATCH_DEPENDENTS].set(atom, new Set()) + if (!batch[BATCH_ATOM_DEPENDENTS].has(atom)) { + batch[BATCH_ATOM_DEPENDENTS].set(atom, new Set()) } - batch[BATCH_ATOM_STATES].set(atom, atomState) + addBatchFuncMedium(batch, () => { + atomState.m?.l.forEach((listener) => listener()) + }) } -const addBatchDependent = (batch: Batch, atom: AnyAtom, dependent: AnyAtom) => { - const dependents = batch[BATCH_DEPENDENTS].get(atom) +const addBatchAtomDependent = ( + batch: Batch, + atom: AnyAtom, + dependent: AnyAtom, +) => { + const dependents = batch[BATCH_ATOM_DEPENDENTS].get(atom) if (dependents) { dependents.add(dependent) } } -const getBatchDependents = (batch: Batch, atom: AnyAtom) => - batch[BATCH_DEPENDENTS].get(atom) +const getBatchAtomDependents = (batch: Batch, atom: AnyAtom) => + batch[BATCH_ATOM_DEPENDENTS].get(atom) -const addBatchFunction = (batch: Batch, fn: () => void) => { - batch[BATCH_FUNCTIONS].add(fn) +const copySetAndClear = (origSet: Set): Set => { + const newSet = new Set(origSet) + origSet.clear() + return newSet } const flushBatch = (batch: Batch) => { @@ -211,14 +227,10 @@ const flushBatch = (batch: Batch) => { } } } - while (batch[BATCH_ATOM_STATES].size || batch[BATCH_FUNCTIONS].size) { - batch[BATCH_DEPENDENTS].clear() - const atomStates = new Set(batch[BATCH_ATOM_STATES].values()) - batch[BATCH_ATOM_STATES].clear() - const functions = new Set(batch[BATCH_FUNCTIONS]) - batch[BATCH_FUNCTIONS].clear() - atomStates.forEach((atomState) => atomState.m?.l.forEach(call)) - functions.forEach(call) + while (batch[BATCH_FUNC_MEDIUM].size || batch[BATCH_FUNC_LOW].size) { + batch[BATCH_ATOM_DEPENDENTS].clear() + copySetAndClear(batch[BATCH_FUNC_MEDIUM]).forEach(call) + copySetAndClear(batch[BATCH_FUNC_LOW]).forEach(call) } if (hasError) { throw error @@ -436,7 +448,7 @@ const buildStore = ( getAtomState(atomWithPendingPromise), ) } - getBatchDependents(batch, atom)?.forEach((dependent) => { + getBatchAtomDependents(batch, atom)?.forEach((dependent) => { dependents.set(dependent, getAtomState(dependent)) }) return dependents @@ -643,7 +655,7 @@ const buildStore = ( isSync = false } } - addBatchFunction(batch, () => { + addBatchFuncLow(batch, () => { const onUnmount = createInvocationContext(batch, () => atomOnMount(atom, (...args) => setAtom(...args)), ) @@ -669,7 +681,7 @@ const buildStore = ( // unmount self const onUnmount = atomState.m.u if (onUnmount) { - addBatchFunction(batch, () => onUnmount(batch)) + addBatchFuncLow(batch, () => onUnmount(batch)) } delete atomState.m if (import.meta.env?.MODE !== 'production') { From b82d070b0433895adaddf82ff6a32b18008e4d60 Mon Sep 17 00:00:00 2001 From: daishi Date: Tue, 17 Dec 2024 18:10:53 +0900 Subject: [PATCH 4/5] refactor: avoid ts warning --- tests/vanilla/store.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/vanilla/store.test.tsx b/tests/vanilla/store.test.tsx index 2d978ad545..0677aa092a 100644 --- a/tests/vanilla/store.test.tsx +++ b/tests/vanilla/store.test.tsx @@ -628,7 +628,7 @@ describe('should invoke flushPending only after all atoms are updated (#2804)', store.sub(a, () => { mountResult.push('a value changed - ' + store.get(a)) }) - const unsub = store.sub(m, () => {}) + store.sub(m, () => {}) mountResult.push('after store.sub') expect(mountResult).not.toEqual([ 'before store.sub', @@ -736,7 +736,7 @@ describe('should mount and trigger listeners even when an error is thrown', () = set(a, 1) get(e) }) - const w = atom(null, async (get, set) => { + const w = atom(null, async (_get, set) => { setTimeout(() => { try { set(b) From 794420f1aecb867ae0c0359285d3a52a0778d5d0 Mon Sep 17 00:00:00 2001 From: daishi Date: Tue, 17 Dec 2024 18:33:45 +0900 Subject: [PATCH 5/5] refactor --- src/vanilla/store.ts | 57 +++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/vanilla/store.ts b/src/vanilla/store.ts index 08958e5ce2..5cd5bb719d 100644 --- a/src/vanilla/store.ts +++ b/src/vanilla/store.ts @@ -161,37 +161,40 @@ const addDependency = ( // Batch // -const BATCH_ATOM_DEPENDENTS = 'd' -const BATCH_FUNC_MEDIUM = 'm' -const BATCH_FUNC_LOW = 'l' - type Batch = Readonly<{ - [BATCH_ATOM_DEPENDENTS]: Map> - [BATCH_FUNC_MEDIUM]: Set<() => void> - [BATCH_FUNC_LOW]: Set<() => void> + /** Atom dependents map */ + D: Map> + /** Medium priority functions */ + M: Set<() => void> + /** Low priority functions */ + L: Set<() => void> }> const createBatch = (): Batch => ({ - [BATCH_ATOM_DEPENDENTS]: new Map(), - [BATCH_FUNC_MEDIUM]: new Set(), - [BATCH_FUNC_LOW]: new Set(), + D: new Map(), + M: new Set(), + L: new Set(), }) const addBatchFuncMedium = (batch: Batch, fn: () => void) => { - batch[BATCH_FUNC_MEDIUM].add(fn) + batch.M.add(fn) } const addBatchFuncLow = (batch: Batch, fn: () => void) => { - batch[BATCH_FUNC_LOW].add(fn) + batch.L.add(fn) } -const addBatchAtom = (batch: Batch, atom: AnyAtom, atomState: AtomState) => { - if (!batch[BATCH_ATOM_DEPENDENTS].has(atom)) { - batch[BATCH_ATOM_DEPENDENTS].set(atom, new Set()) +const registerBatchAtom = ( + batch: Batch, + atom: AnyAtom, + atomState: AtomState, +) => { + if (!batch.D.has(atom)) { + batch.D.set(atom, new Set()) + addBatchFuncMedium(batch, () => { + atomState.m?.l.forEach((listener) => listener()) + }) } - addBatchFuncMedium(batch, () => { - atomState.m?.l.forEach((listener) => listener()) - }) } const addBatchAtomDependent = ( @@ -199,14 +202,14 @@ const addBatchAtomDependent = ( atom: AnyAtom, dependent: AnyAtom, ) => { - const dependents = batch[BATCH_ATOM_DEPENDENTS].get(atom) + const dependents = batch.D.get(atom) if (dependents) { dependents.add(dependent) } } const getBatchAtomDependents = (batch: Batch, atom: AnyAtom) => - batch[BATCH_ATOM_DEPENDENTS].get(atom) + batch.D.get(atom) const copySetAndClear = (origSet: Set): Set => { const newSet = new Set(origSet) @@ -227,10 +230,10 @@ const flushBatch = (batch: Batch) => { } } } - while (batch[BATCH_FUNC_MEDIUM].size || batch[BATCH_FUNC_LOW].size) { - batch[BATCH_ATOM_DEPENDENTS].clear() - copySetAndClear(batch[BATCH_FUNC_MEDIUM]).forEach(call) - copySetAndClear(batch[BATCH_FUNC_LOW]).forEach(call) + while (batch.M.size || batch.L.size) { + batch.D.clear() + copySetAndClear(batch.M).forEach(call) + copySetAndClear(batch.L).forEach(call) } if (hasError) { throw error @@ -526,7 +529,7 @@ const buildStore = ( readAtomState(batch, a, markedAtoms) mountDependencies(batch, a, aState) if (prevEpochNumber !== aState.n) { - addBatchAtom(batch, a, aState) + registerBatchAtom(batch, a, aState) changedAtoms.add(a) } } @@ -558,7 +561,7 @@ const buildStore = ( setAtomStateValueOrPromise(a, aState, v) mountDependencies(batch, a, aState) if (prevEpochNumber !== aState.n) { - addBatchAtom(batch, a, aState) + registerBatchAtom(batch, a, aState) recomputeDependents(batch, a, aState) } return undefined as R @@ -744,7 +747,7 @@ const buildStore = ( setAtomStateValueOrPromise(atom, atomState, value) mountDependencies(batch, atom, atomState) if (prevEpochNumber !== atomState.n) { - addBatchAtom(batch, atom, atomState) + registerBatchAtom(batch, atom, atomState) recomputeDependents(batch, atom, atomState) } }