Skip to content

Commit 5a2d74b

Browse files
committed
Add benchmarks for resultEqualityCheck performance impact
1 parent c46f8bf commit 5a2d74b

File tree

1 file changed

+190
-0
lines changed

1 file changed

+190
-0
lines changed
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
import type { AnyFunction } from '@internal/types'
2+
import type { OutputSelector, Selector } from 'reselect'
3+
import {
4+
createSelector,
5+
lruMemoize,
6+
referenceEqualityCheck,
7+
weakMapMemoize
8+
} from 'reselect'
9+
import type { Options } from 'tinybench'
10+
import { bench } from 'vitest'
11+
import {
12+
logSelectorRecomputations,
13+
setFunctionNames,
14+
setupStore,
15+
toggleCompleted,
16+
type RootState
17+
} from '../testUtils'
18+
19+
describe('memoize functions performance with resultEqualityCheck set to referenceEqualityCheck vs. without resultEqualityCheck', () => {
20+
describe('comparing selectors created with createSelector', () => {
21+
const store = setupStore()
22+
23+
const arrayOfNumbers = Array.from({ length: 1_000 }, (num, index) => index)
24+
25+
const commonOptions: Options = {
26+
iterations: 10_000,
27+
time: 0
28+
}
29+
30+
const runSelector = <S extends Selector>(selector: S) => {
31+
arrayOfNumbers.forEach(num => {
32+
selector(store.getState())
33+
})
34+
}
35+
36+
const createAppSelector = createSelector.withTypes<RootState>()
37+
38+
const selectTodoIdsWeakMap = createAppSelector(
39+
[state => state.todos],
40+
todos => todos.map(({ id }) => id)
41+
)
42+
43+
const selectTodoIdsWeakMapWithResultEqualityCheck = createAppSelector(
44+
[state => state.todos],
45+
todos => todos.map(({ id }) => id),
46+
{
47+
memoizeOptions: { resultEqualityCheck: referenceEqualityCheck },
48+
argsMemoizeOptions: { resultEqualityCheck: referenceEqualityCheck }
49+
}
50+
)
51+
52+
const selectTodoIdsLru = createAppSelector(
53+
[state => state.todos],
54+
todos => todos.map(({ id }) => id),
55+
{ memoize: lruMemoize, argsMemoize: lruMemoize }
56+
)
57+
58+
const selectTodoIdsLruWithResultEqualityCheck = createAppSelector(
59+
[state => state.todos],
60+
todos => todos.map(({ id }) => id),
61+
{
62+
memoize: lruMemoize,
63+
memoizeOptions: { resultEqualityCheck: referenceEqualityCheck },
64+
argsMemoize: lruMemoize,
65+
argsMemoizeOptions: { resultEqualityCheck: referenceEqualityCheck }
66+
}
67+
)
68+
69+
const selectors = {
70+
selectTodoIdsWeakMap,
71+
selectTodoIdsWeakMapWithResultEqualityCheck,
72+
selectTodoIdsLru,
73+
selectTodoIdsLruWithResultEqualityCheck
74+
}
75+
76+
setFunctionNames(selectors)
77+
78+
const createOptions = <S extends OutputSelector>(selector: S) => {
79+
const options: Options = {
80+
setup: (task, mode) => {
81+
if (mode === 'warmup') return
82+
83+
task.opts = {
84+
beforeEach: () => {
85+
store.dispatch(toggleCompleted(1))
86+
},
87+
88+
afterAll: () => {
89+
logSelectorRecomputations(selector)
90+
}
91+
}
92+
}
93+
}
94+
return { ...commonOptions, ...options }
95+
}
96+
97+
Object.values(selectors).forEach(selector => {
98+
bench(
99+
selector,
100+
() => {
101+
runSelector(selector)
102+
},
103+
createOptions(selector)
104+
)
105+
})
106+
})
107+
108+
describe('comparing selectors created with memoize functions', () => {
109+
const store = setupStore()
110+
111+
const arrayOfNumbers = Array.from(
112+
{ length: 100_000 },
113+
(num, index) => index
114+
)
115+
116+
const commonOptions: Options = {
117+
iterations: 1000,
118+
time: 0
119+
}
120+
121+
const runSelector = <S extends Selector>(selector: S) => {
122+
arrayOfNumbers.forEach(num => {
123+
selector(store.getState())
124+
})
125+
}
126+
127+
const selectTodoIdsWeakMap = weakMapMemoize((state: RootState) =>
128+
state.todos.map(({ id }) => id)
129+
)
130+
131+
const selectTodoIdsWeakMapWithResultEqualityCheck = weakMapMemoize(
132+
(state: RootState) => state.todos.map(({ id }) => id),
133+
{ resultEqualityCheck: referenceEqualityCheck }
134+
)
135+
136+
const selectTodoIdsLru = lruMemoize((state: RootState) =>
137+
state.todos.map(({ id }) => id)
138+
)
139+
140+
const selectTodoIdsLruWithResultEqualityCheck = lruMemoize(
141+
(state: RootState) => state.todos.map(({ id }) => id),
142+
{ resultEqualityCheck: referenceEqualityCheck }
143+
)
144+
145+
const memoizedFunctions = {
146+
selectTodoIdsWeakMap,
147+
selectTodoIdsWeakMapWithResultEqualityCheck,
148+
selectTodoIdsLru,
149+
selectTodoIdsLruWithResultEqualityCheck
150+
}
151+
152+
setFunctionNames(memoizedFunctions)
153+
154+
const createOptions = <
155+
Func extends AnyFunction & { resultsCount: () => number }
156+
>(
157+
memoizedFunction: Func
158+
) => {
159+
const options: Options = {
160+
setup: (task, mode) => {
161+
if (mode === 'warmup') return
162+
163+
task.opts = {
164+
beforeEach: () => {
165+
store.dispatch(toggleCompleted(1))
166+
},
167+
168+
afterAll: () => {
169+
console.log(
170+
memoizedFunction.name,
171+
memoizedFunction.resultsCount()
172+
)
173+
}
174+
}
175+
}
176+
}
177+
return { ...commonOptions, ...options }
178+
}
179+
180+
Object.values(memoizedFunctions).forEach(memoizedFunction => {
181+
bench(
182+
memoizedFunction,
183+
() => {
184+
runSelector(memoizedFunction)
185+
},
186+
createOptions(memoizedFunction)
187+
)
188+
})
189+
})
190+
})

0 commit comments

Comments
 (0)