Description
Describe the bug
Context
Our libraries state is an array of objects. The deepest nesting level is maybe another object in each object.
Having array sizes of thousands of elements is not unheard of and has been completely manageable performance-wise in Svelte 4.
Issue:
Because this array is representing state I converted what was previously a store into a deeply reactive state.
I am observing quite a heavy performance impact. The surprising part is that this is not only limited to the rendering of components based on that state, but also affects simple access of the array in a non-stateful context.
For reference, iterating over an array with 1000 objects of type { position: { x: number, y: number } }
yields quite different results - deeply reactive state however, is very far off.
Here are the results of a simple benchmark comparing $state(array)
to $state.frozen(array)
and to simply accessing the array itself. The function used for taking the measurements is a simple summation (see REPL below for full code).
let sum = 0;
for (const elem of array) {
sum += elem.position.x + elem.position.y;
}
+--------------+---------+--------------------+--------+---------+
| Task Name | ops/sec | Average Time (ns) | Margin | Samples |
+--------------+---------+--------------------+--------+---------+
| baseline | 465,124 | 2149.9602650215506 | ±6.13% | 46559 |
| frozen state | 161,428 | 6194.690263273545 | ±6.10% | 16159 |
| deep state | 5,890 | 169779.2869269949 | ±3.03% | 589 |
+--------------+---------+--------------------+--------+---------+
Is this expected, or am I doing something wrong here? I test my code with production builds and can observe similar behavior, but am I accidentally benchmarking dev mode in the REPL?
Can I bail out of the runtime reactivity code path when I simply want to access state programmatically in an unstateful manner?
Reproduction
REPL with benchmark. Check performance tab when hitting change stuff
to observe rendering performance.
Logs
No response
System Info
Severity
annoyance