Skip to content

Commit 4a8bdea

Browse files
fix(store): improve performance by ~4x (#236)
* refactor(store): improve __flush_internals performance by pre-sorting derived deps * ci: apply automated fixes and generate docs * check unicity of deps * ci: apply automated fixes and generate docs * registerOnGraph only sort when pushing in array --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent dfbb669 commit 4a8bdea

File tree

5 files changed

+31
-24
lines changed

5 files changed

+31
-24
lines changed

docs/reference/classes/derived.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ Defined in: [derived.ts:68](https://github.com/TanStack/store/blob/main/packages
9393
checkIfRecalculationNeededDeeply(): void
9494
```
9595

96-
Defined in: [derived.ts:162](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L162)
96+
Defined in: [derived.ts:178](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L178)
9797

9898
#### Returns
9999

@@ -139,7 +139,7 @@ prevVal: undefined | NonNullable<TState>;
139139
mount(): () => void
140140
```
141141

142-
Defined in: [derived.ts:183](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L183)
142+
Defined in: [derived.ts:199](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L199)
143143

144144
#### Returns
145145

@@ -157,7 +157,7 @@ Defined in: [derived.ts:183](https://github.com/TanStack/store/blob/main/package
157157
recompute(): void
158158
```
159159

160-
Defined in: [derived.ts:154](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L154)
160+
Defined in: [derived.ts:170](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L170)
161161

162162
#### Returns
163163

@@ -193,7 +193,7 @@ readonly (
193193
subscribe(listener): () => void
194194
```
195195

196-
Defined in: [derived.ts:195](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L195)
196+
Defined in: [derived.ts:211](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L211)
197197

198198
#### Parameters
199199

@@ -217,7 +217,7 @@ Defined in: [derived.ts:195](https://github.com/TanStack/store/blob/main/package
217217
unregisterFromGraph(deps): void
218218
```
219219

220-
Defined in: [derived.ts:134](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L134)
220+
Defined in: [derived.ts:147](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L147)
221221

222222
#### Parameters
223223

docs/reference/functions/batch.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ title: batch
1111
function batch(fn): void
1212
```
1313

14-
Defined in: [scheduler.ts:142](https://github.com/TanStack/store/blob/main/packages/store/src/scheduler.ts#L142)
14+
Defined in: [scheduler.ts:133](https://github.com/TanStack/store/blob/main/packages/store/src/scheduler.ts#L133)
1515

1616
## Parameters
1717

docs/reference/variables/storetoderived.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ title: __storeToDerived
88
# Variable: \_\_storeToDerived
99

1010
```ts
11-
const __storeToDerived: WeakMap<Store<unknown, (cb) => unknown>, Set<Derived<unknown, readonly any[]>>>;
11+
const __storeToDerived: WeakMap<Store<unknown, (cb) => unknown>, Derived<unknown, readonly any[]>[]>;
1212
```
1313

1414
Defined in: [scheduler.ts:19](https://github.com/TanStack/store/blob/main/packages/store/src/scheduler.ts#L19)

packages/store/src/derived.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export class Derived<
105105
registerOnGraph(
106106
deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,
107107
) {
108+
const toSort = new Set<Array<Derived<unknown>>>()
108109
for (const dep of deps) {
109110
if (dep instanceof Derived) {
110111
// First register the intermediate derived value if it's not already registered
@@ -115,10 +116,12 @@ export class Derived<
115116
// Register the derived as related derived to the store
116117
let relatedLinkedDerivedVals = __storeToDerived.get(dep)
117118
if (!relatedLinkedDerivedVals) {
118-
relatedLinkedDerivedVals = new Set()
119+
relatedLinkedDerivedVals = [this as never]
119120
__storeToDerived.set(dep, relatedLinkedDerivedVals)
121+
} else if (!relatedLinkedDerivedVals.includes(this as never)) {
122+
relatedLinkedDerivedVals.push(this as never)
123+
toSort.add(relatedLinkedDerivedVals)
120124
}
121-
relatedLinkedDerivedVals.add(this as never)
122125

123126
// Register the store as a related store to this derived
124127
let relatedStores = __derivedToStore.get(this as never)
@@ -129,6 +132,16 @@ export class Derived<
129132
relatedStores.add(dep)
130133
}
131134
}
135+
for (const arr of toSort) {
136+
// First sort deriveds by dependency order
137+
arr.sort((a, b) => {
138+
// If a depends on b, b should go first
139+
if (a instanceof Derived && a.options.deps.includes(b)) return 1
140+
// If b depends on a, a should go first
141+
if (b instanceof Derived && b.options.deps.includes(a)) return -1
142+
return 0
143+
})
144+
}
132145
}
133146

134147
unregisterFromGraph(
@@ -140,7 +153,10 @@ export class Derived<
140153
} else if (dep instanceof Store) {
141154
const relatedLinkedDerivedVals = __storeToDerived.get(dep)
142155
if (relatedLinkedDerivedVals) {
143-
relatedLinkedDerivedVals.delete(this as never)
156+
relatedLinkedDerivedVals.splice(
157+
relatedLinkedDerivedVals.indexOf(this as never),
158+
1,
159+
)
144160
}
145161

146162
const relatedStores = __derivedToStore.get(this as never)

packages/store/src/scheduler.ts

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Derived } from './derived'
1+
import type { Derived } from './derived'
22
import type { Store } from './store'
33

44
/**
@@ -18,7 +18,7 @@ import type { Store } from './store'
1818
*/
1919
export const __storeToDerived = new WeakMap<
2020
Store<unknown>,
21-
Set<Derived<unknown>>
21+
Array<Derived<unknown>>
2222
>()
2323
export const __derivedToStore = new WeakMap<
2424
Derived<unknown>,
@@ -35,17 +35,8 @@ const __pendingUpdates = new Set<Store<unknown>>()
3535
// Add a map to store initial values before batch
3636
const __initialBatchValues = new Map<Store<unknown>, unknown>()
3737

38-
function __flush_internals(relatedVals: Set<Derived<unknown>>) {
39-
// First sort deriveds by dependency order
40-
const sorted = Array.from(relatedVals).sort((a, b) => {
41-
// If a depends on b, b should go first
42-
if (a instanceof Derived && a.options.deps.includes(b)) return 1
43-
// If b depends on a, a should go first
44-
if (b instanceof Derived && b.options.deps.includes(a)) return -1
45-
return 0
46-
})
47-
48-
for (const derived of sorted) {
38+
function __flush_internals(relatedVals: ReadonlyArray<Derived<unknown>>) {
39+
for (const derived of relatedVals) {
4940
if (__depsThatHaveWrittenThisTick.current.includes(derived)) {
5041
continue
5142
}
@@ -57,7 +48,7 @@ function __flush_internals(relatedVals: Set<Derived<unknown>>) {
5748
if (stores) {
5849
for (const store of stores) {
5950
const relatedLinkedDerivedVals = __storeToDerived.get(store)
60-
if (!relatedLinkedDerivedVals) continue
51+
if (!relatedLinkedDerivedVals?.length) continue
6152
__flush_internals(relatedLinkedDerivedVals)
6253
}
6354
}

0 commit comments

Comments
 (0)