fix(signal): reduce duplicate observer registrations in repeated signal reads#2660
fix(signal): reduce duplicate observer registrations in repeated signal reads#2660oanlit wants to merge 2 commits into
Conversation
|
|
Thanks for digging into this. The repeated registration issue is real, but I wanted to avoid adding extra signal state or exposing internal SignalState through the createSignal return tuple for testing. I landed a smaller version in fae8fbe that uses the existing observer slot structure instead: when the current listener is already the last observer for a source, readSignal skips adding another source/observer pair. This keeps the common repeated-read case from growing the tracking arrays while avoiding new cleanup state. I also added behavior coverage for repeated reads, disposal cleanup, and conditional dependency cleanup/re-subscription. Thanks again for identifying the issue and providing the repro direction. |
Summary
When a signal is read repeatedly within the same computation (e.g. inside loops),
the current implementation registers the same observer multiple times.
This leads to unnecessary growth of internal tracking structures, including:
observersobserverSlotssourcessourceSlotsThis issue is especially noticeable in patterns such as:
In these cases, repeated signal reads (e.g.
length, indexed access, or direct signal calls)cause the same computation to be registered multiple times.
This PR introduces a lightweight deduplication mechanism by tracking the last registered observer per signal.
lastObservertoSignalStatelastObserverlastObserverduring cleanupThis significantly reduces redundant registrations in common scenarios while keeping the cost of deduplication O(1) and preserving existing behavior.
How did I test this change?
To enable verification of internal observer behavior in tests, this PR slightly adjusts the return value of
createSignal:Before this change:
observers.length === 1000After this change:
observers.length === 1Confirmed that repeated reads (e.g.
lengthand indexed access) no longercause excessive observer registrations.
pnpm build pnpm testAll tests pass.
observerSlotsandsourceSlotsno longer grow excessively