Skip to content

Commit

Permalink
add single recomputeDependents to batch
Browse files Browse the repository at this point in the history
  • Loading branch information
dmaskasky committed Jan 8, 2025
1 parent 023480c commit 28a45f6
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 27 deletions.
44 changes: 20 additions & 24 deletions src/vanilla/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,11 @@ type BatchPriority = 0 | 1 | 2

type Batch = [
/** high priority listeners */
priority0: Set<() => void>,
priority0: Set<(batch: Batch) => void>,
/** atom listeners */
priority1: Set<() => void>,
priority1: Set<(batch: Batch) => void>,
/** atom mount hooks */
priority2: Set<() => void>,
priority2: Set<(batch: Batch) => void>,
] & {
/** changed Atoms */
C: Set<AnyAtom>
Expand All @@ -189,7 +189,7 @@ const createBatch = (): Batch =>
const addBatchFunc = (
batch: Batch,
priority: BatchPriority,
fn: () => void,
fn: (batch: Batch) => void,
) => {
batch[priority].add(fn)
}
Expand All @@ -203,21 +203,20 @@ const registerBatchAtom = (
batch.C.add(atom)
atomState.u?.(batch)
const scheduleListeners = () => {
atomState.m?.l.forEach((listener) => addBatchFunc(batch, 1, listener))
atomState.m?.l.forEach((listener) =>
addBatchFunc(batch, 1, () => listener()),
)
}
addBatchFunc(batch, 1, scheduleListeners)
}
}

const flushBatch = (
batch: Batch,
recomputeDependents: (batch: Batch) => void,
) => {
const flushBatch = (batch: Batch) => {
let error: AnyError
let hasError = false
const call = (fn: () => void) => {
const call = (fn: (batch: Batch) => void) => {
try {
fn()
fn(batch)
} catch (e) {
if (!hasError) {
error = e
Expand All @@ -226,8 +225,6 @@ const flushBatch = (
}
}
while (batch.C.size || batch.some((channel) => channel.size)) {
recomputeDependents(batch)
batch.C.clear()
for (const channel of batch) {
channel.forEach(call)
channel.clear()
Expand Down Expand Up @@ -380,7 +377,7 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
const batch = createBatch()
addDependency(atom, atomState, a, aState)
mountDependencies(batch, atom, atomState)
recomputeAndFlushBatch(batch)
flushBatch(batch)
}
}
}
Expand Down Expand Up @@ -422,7 +419,7 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
if (atomState.m) {
const batch = createBatch()
mountDependencies(batch, atom, atomState)
recomputeAndFlushBatch(batch)
flushBatch(batch)
}
}
valueOrPromise.then(complete, complete)
Expand Down Expand Up @@ -539,11 +536,9 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
}
delete aState.x
}
batch.C.clear()
}

const recomputeAndFlushBatch = (batch: Batch) =>
flushBatch(batch, recomputeDependents)

const writeAtomState = <Value, Args extends unknown[], Result>(
batch: Batch,
atom: WritableAtom<Value, Args, Result>,
Expand All @@ -569,6 +564,7 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
mountDependencies(batch, a, aState)
if (prevEpochNumber !== aState.n) {
dirtyDependents(aState)
addBatchFunc(batch, 0, recomputeDependents)
registerBatchAtom(batch, a, aState)
}
return undefined as R
Expand All @@ -577,7 +573,7 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
}
} finally {
if (!isSync) {
recomputeAndFlushBatch(batch)
flushBatch(batch)
}
}
}
Expand All @@ -596,7 +592,7 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
try {
return writeAtomState(batch, atom, ...args)
} finally {
recomputeAndFlushBatch(batch)
flushBatch(batch)
}
}

Expand Down Expand Up @@ -653,7 +649,7 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
return writeAtomState(batch, atom, ...args)
} finally {
if (!isSync) {
recomputeAndFlushBatch(batch)
flushBatch(batch)
}
}
}
Expand Down Expand Up @@ -690,7 +686,7 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
// unmount self
const onUnmount = atomState.m.u
if (onUnmount) {
addBatchFunc(batch, 2, () => onUnmount(batch))
addBatchFunc(batch, 2, onUnmount)
}
delete atomState.m
atomState.h?.(batch)
Expand All @@ -710,12 +706,12 @@ const buildStore = (...storeArgs: StoreArgs): Store => {
const mounted = mountAtom(batch, atom, atomState)
const listeners = mounted.l
listeners.add(listener)
recomputeAndFlushBatch(batch)
flushBatch(batch)
return () => {
listeners.delete(listener)
const batch = createBatch()
unmountAtom(batch, atom, atomState)
recomputeAndFlushBatch(batch)
flushBatch(batch)
}
}

Expand Down
17 changes: 14 additions & 3 deletions tests/vanilla/effect.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { expect, it, vi } from 'vitest'
import type { Atom, Getter, Setter } from 'jotai/vanilla'
import type { Atom, Getter, PrimitiveAtom, Setter } from 'jotai/vanilla'
import { atom, createStore } from 'jotai/vanilla'

type Store = ReturnType<typeof createStore>
type GetAtomState = Parameters<Parameters<Store['unstable_derive']>[0]>[0]
type AtomState = NonNullable<ReturnType<GetAtomState>>
type Batch = Parameters<NonNullable<AtomState['u']>>[0]
type AnyAtom = Atom<unknown>

type Cleanup = () => void
Expand Down Expand Up @@ -59,7 +60,7 @@ function syncEffect(effect: Effect): Atom<void> {
store.set(refreshAtom, (v) => v + 1)
} else {
// unmount
batch[0].add(() => {
scheduleListener(batch, () => {
ref.cleanup?.()
delete ref.cleanup
})
Expand All @@ -69,7 +70,17 @@ function syncEffect(effect: Effect): Atom<void> {
internalAtomState.u = (batch) => {
originalUpdateHook?.(batch)
// update
batch[0].add(runEffect)
scheduleListener(batch, runEffect)
}
function scheduleListener(batch: Batch, listener: () => void) {
if (batch[0].size === 0) {
store.set(
atom(0, function (this: PrimitiveAtom<number>, _, set) {
set(this, 1)
}),
)
}
batch[0].add(listener)
}
}
return atom((get) => {
Expand Down

0 comments on commit 28a45f6

Please sign in to comment.