Skip to content

Commit aea5843

Browse files
committed
add single recomputeDependents to batch
1 parent 023480c commit aea5843

File tree

2 files changed

+41
-29
lines changed

2 files changed

+41
-29
lines changed

src/vanilla/store.ts

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,11 @@ type BatchPriority = 0 | 1 | 2
173173

174174
type Batch = [
175175
/** high priority listeners */
176-
priority0: Set<() => void>,
176+
priority0: Set<(batch: Batch) => void>,
177177
/** atom listeners */
178-
priority1: Set<() => void>,
178+
priority1: Set<(batch: Batch) => void>,
179179
/** atom mount hooks */
180-
priority2: Set<() => void>,
180+
priority2: Set<(batch: Batch) => void>,
181181
] & {
182182
/** changed Atoms */
183183
C: Set<AnyAtom>
@@ -189,7 +189,7 @@ const createBatch = (): Batch =>
189189
const addBatchFunc = (
190190
batch: Batch,
191191
priority: BatchPriority,
192-
fn: () => void,
192+
fn: (batch: Batch) => void,
193193
) => {
194194
batch[priority].add(fn)
195195
}
@@ -203,21 +203,20 @@ const registerBatchAtom = (
203203
batch.C.add(atom)
204204
atomState.u?.(batch)
205205
const scheduleListeners = () => {
206-
atomState.m?.l.forEach((listener) => addBatchFunc(batch, 1, listener))
206+
atomState.m?.l.forEach((listener) =>
207+
addBatchFunc(batch, 1, () => listener()),
208+
)
207209
}
208210
addBatchFunc(batch, 1, scheduleListeners)
209211
}
210212
}
211213

212-
const flushBatch = (
213-
batch: Batch,
214-
recomputeDependents: (batch: Batch) => void,
215-
) => {
214+
const flushBatch = (batch: Batch) => {
216215
let error: AnyError
217216
let hasError = false
218-
const call = (fn: () => void) => {
217+
const call = (fn: (batch: Batch) => void) => {
219218
try {
220-
fn()
219+
fn(batch)
221220
} catch (e) {
222221
if (!hasError) {
223222
error = e
@@ -226,8 +225,6 @@ const flushBatch = (
226225
}
227226
}
228227
while (batch.C.size || batch.some((channel) => channel.size)) {
229-
recomputeDependents(batch)
230-
batch.C.clear()
231228
for (const channel of batch) {
232229
channel.forEach(call)
233230
channel.clear()
@@ -380,7 +377,7 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
380377
const batch = createBatch()
381378
addDependency(atom, atomState, a, aState)
382379
mountDependencies(batch, atom, atomState)
383-
recomputeAndFlushBatch(batch)
380+
flushBatch(batch)
384381
}
385382
}
386383
}
@@ -422,7 +419,7 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
422419
if (atomState.m) {
423420
const batch = createBatch()
424421
mountDependencies(batch, atom, atomState)
425-
recomputeAndFlushBatch(batch)
422+
flushBatch(batch)
426423
}
427424
}
428425
valueOrPromise.then(complete, complete)
@@ -445,13 +442,18 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
445442
atomState: AtomState<Value>,
446443
): Map<AnyAtom, AtomState> => {
447444
const mountedDependents = new Map<AnyAtom, AtomState>()
448-
const dependents = new Set([...(atomState.m?.t || []), ...atomState.p])
449-
for (const a of dependents) {
445+
for (const a of atomState.m?.t || []) {
450446
const aState = ensureAtomState(a)
451447
if (aState.m) {
452448
mountedDependents.set(a, aState)
453449
}
454450
}
451+
for (const atomWithPendingPromise of atomState.p) {
452+
mountedDependents.set(
453+
atomWithPendingPromise,
454+
ensureAtomState(atomWithPendingPromise),
455+
)
456+
}
455457
return mountedDependents
456458
}
457459

@@ -539,11 +541,9 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
539541
}
540542
delete aState.x
541543
}
544+
batch.C.clear()
542545
}
543546

544-
const recomputeAndFlushBatch = (batch: Batch) =>
545-
flushBatch(batch, recomputeDependents)
546-
547547
const writeAtomState = <Value, Args extends unknown[], Result>(
548548
batch: Batch,
549549
atom: WritableAtom<Value, Args, Result>,
@@ -569,6 +569,7 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
569569
mountDependencies(batch, a, aState)
570570
if (prevEpochNumber !== aState.n) {
571571
dirtyDependents(aState)
572+
addBatchFunc(batch, 0, recomputeDependents)
572573
registerBatchAtom(batch, a, aState)
573574
}
574575
return undefined as R
@@ -577,7 +578,7 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
577578
}
578579
} finally {
579580
if (!isSync) {
580-
recomputeAndFlushBatch(batch)
581+
flushBatch(batch)
581582
}
582583
}
583584
}
@@ -596,7 +597,7 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
596597
try {
597598
return writeAtomState(batch, atom, ...args)
598599
} finally {
599-
recomputeAndFlushBatch(batch)
600+
flushBatch(batch)
600601
}
601602
}
602603

@@ -653,7 +654,7 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
653654
return writeAtomState(batch, atom, ...args)
654655
} finally {
655656
if (!isSync) {
656-
recomputeAndFlushBatch(batch)
657+
flushBatch(batch)
657658
}
658659
}
659660
}
@@ -690,7 +691,7 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
690691
// unmount self
691692
const onUnmount = atomState.m.u
692693
if (onUnmount) {
693-
addBatchFunc(batch, 2, () => onUnmount(batch))
694+
addBatchFunc(batch, 2, onUnmount)
694695
}
695696
delete atomState.m
696697
atomState.h?.(batch)
@@ -710,12 +711,12 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
710711
const mounted = mountAtom(batch, atom, atomState)
711712
const listeners = mounted.l
712713
listeners.add(listener)
713-
recomputeAndFlushBatch(batch)
714+
flushBatch(batch)
714715
return () => {
715716
listeners.delete(listener)
716717
const batch = createBatch()
717718
unmountAtom(batch, atom, atomState)
718-
recomputeAndFlushBatch(batch)
719+
flushBatch(batch)
719720
}
720721
}
721722

tests/vanilla/effect.test.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { expect, it, vi } from 'vitest'
2-
import type { Atom, Getter, Setter } from 'jotai/vanilla'
2+
import type { Atom, Getter, PrimitiveAtom, Setter } from 'jotai/vanilla'
33
import { atom, createStore } from 'jotai/vanilla'
44

55
type Store = ReturnType<typeof createStore>
66
type GetAtomState = Parameters<Parameters<Store['unstable_derive']>[0]>[0]
77
type AtomState = NonNullable<ReturnType<GetAtomState>>
8+
type Batch = Parameters<NonNullable<AtomState['u']>>[0]
89
type AnyAtom = Atom<unknown>
910

1011
type Cleanup = () => void
@@ -59,7 +60,7 @@ function syncEffect(effect: Effect): Atom<void> {
5960
store.set(refreshAtom, (v) => v + 1)
6061
} else {
6162
// unmount
62-
batch[0].add(() => {
63+
scheduleListener(batch, () => {
6364
ref.cleanup?.()
6465
delete ref.cleanup
6566
})
@@ -69,7 +70,17 @@ function syncEffect(effect: Effect): Atom<void> {
6970
internalAtomState.u = (batch) => {
7071
originalUpdateHook?.(batch)
7172
// update
72-
batch[0].add(runEffect)
73+
scheduleListener(batch, runEffect)
74+
}
75+
function scheduleListener(batch: Batch, listener: () => void) {
76+
if (batch[0].size === 0) {
77+
store.set(
78+
atom(0, function (this: PrimitiveAtom<number>, _, set) {
79+
set(this, 1)
80+
}),
81+
)
82+
}
83+
batch[0].add(listener)
7384
}
7485
}
7586
return atom((get) => {

0 commit comments

Comments
 (0)