Skip to content

Commit

Permalink
process all batch functions even on error
Browse files Browse the repository at this point in the history
  • Loading branch information
dmaskasky committed Dec 18, 2024
1 parent 2499f3d commit 46637d0
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 59 deletions.
14 changes: 5 additions & 9 deletions src/vanilla/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ const registerBatchAtom = (
if (!batch.D.has(atom)) {
batch.D.set(atom, new Set())
addBatchFuncMedium(batch, () => {
atomState.m?.l.forEach((listener) => listener())
atomState.m?.l.forEach((listener) => addBatchFuncMedium(batch, listener))
})
}
}
Expand All @@ -211,12 +211,6 @@ const addBatchAtomDependent = (
const getBatchAtomDependents = (batch: Batch, atom: AnyAtom) =>
batch.D.get(atom)

const copySetAndClear = <T>(origSet: Set<T>): Set<T> => {
const newSet = new Set(origSet)
origSet.clear()
return newSet
}

const flushBatch = (batch: Batch) => {
let error: AnyError
let hasError = false
Expand All @@ -232,8 +226,10 @@ const flushBatch = (batch: Batch) => {
}
while (batch.M.size || batch.L.size) {
batch.D.clear()
copySetAndClear(batch.M).forEach(call)
copySetAndClear(batch.L).forEach(call)
batch.M.forEach(call)
batch.M.clear()
batch.L.forEach(call)
batch.L.clear()
}
if (hasError) {
throw error
Expand Down
75 changes: 25 additions & 50 deletions tests/vanilla/store.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ import { waitFor } from '@testing-library/react'
import { assert, describe, expect, it, vi } from 'vitest'
import { atom, createStore } from 'jotai/vanilla'
import type { Atom, Getter, PrimitiveAtom } from 'jotai/vanilla'
import type {
INTERNAL_DevStoreRev4,
INTERNAL_PrdStore,
} from 'jotai/vanilla/store'

it('should not fire on subscribe', async () => {
const store = createStore()
Expand Down Expand Up @@ -316,52 +312,6 @@ it('should update derived atoms during write (#2107)', async () => {
expect(store.get(countAtom)).toBe(2)
})

it.only('mounts dependencies in async edge case', async () => {
const store = createStore().unstable_derive((getAtomState, ...rest) => [
(a) => Object.assign(getAtomState(a), { label: a.debugLabel }),
...rest,
]) as INTERNAL_DevStoreRev4 & INTERNAL_PrdStore
const getAtomState = store.dev4_get_internal_weak_map().get

const a = atom(0)
a.debugLabel = 'a'
const resolve: (() => void)[] = []
const b = atom((get) => {
get(a)
return new Promise<void>((r) => {
resolve.push(() => {
r()
})
})
})
b.debugLabel = 'b'
const c = atom(async (get) => {
await Promise.resolve()
await get(b)
})
c.debugLabel = 'c'

store.sub(c, () => {})

await Promise.resolve()
expect(resolve.length).toBe(1)
resolve[0]!()
// --- Need to wait two microtasks to make it work ---
await Promise.resolve()
await Promise.resolve()
const aState = getAtomState(a)
const bState = getAtomState(b)
const cState = getAtomState(c)
console.log('aState', aState)
console.log('bState', bState)
console.log('cState', cState)

store.set(a, 20)
store.set(a, 30)
await Promise.resolve()
expect(resolve.length).toBe(3)
})

it('resolves dependencies reliably after a delay (#2192)', async () => {
expect.assertions(1)
const countAtom = atom(0)
Expand Down Expand Up @@ -1016,3 +966,28 @@ it('processes deep atom a graph beyond maxDepth', () => {
expect(() => store.set(baseAtom, 1)).not.toThrow()
// store.set(lastAtom) // FIXME: This is causing a stack overflow
})

it('should process all atom listeners even if some of them throw errors', () => {
const store = createStore()
const a = atom(0)
const listenerA = vi.fn()
const listenerB = vi.fn(() => {
throw new Error('error')
})
const listenerC = vi.fn()
const listenerD = vi.fn()

store.sub(a, listenerA)
store.sub(a, listenerB)
store.sub(a, listenerC)
store.sub(a, listenerD)
try {
store.set(a, 1)
} catch {
// expect empty
}
expect(listenerA).toHaveBeenCalledTimes(1)
expect(listenerB).toHaveBeenCalledTimes(1)
expect(listenerC).toHaveBeenCalledTimes(1)
expect(listenerD).toHaveBeenCalledTimes(1)
})

0 comments on commit 46637d0

Please sign in to comment.