Skip to main content

Scalability

We designed Signia to scale well with data-intensive applications. There are a few special features that make this possible:

Incrementally computed signals

Reactive state libraries have a notion of 'computed' values which cannot be modified directly, but are automatically recomputed when their dependencies change.

Most (if not all) other such libraries do this recomputation from scratch every time a dependency changes. This is fine for most situations, but it doesn't work well if the computed signal is expensive to compute and changes often, perhaps blocking UI updates.

Signia gives you the option to compute new values incrementally. You typically do this by collecting 'diffs' of the changes to dependencies, and applying them to the previous value. It requires a little more work and care, but it typically will only need to happen in a handful of places for even the most complex applications.

See Incrementally Computed Signals for more details.

Always-on Caching of computed values

Most reactive libraries will cache computed values to avoid unnecessary recomputation. However, most reactive libraries also throw away the cached values when they are no longer being actively 'listened' to.

This sounds reasonable, but some applications feature computed values that are used frequently but not actively 'listened' to. For example, in tldraw, we have some computed representations of the scene graph that are not actually used to render the scene, but are used when performing hit testing on pointer-move events. Since handling pointer-move events does not count as 'active listening', in other reactive frameworks our entire scene graph would be thrown away and recomputed every time the mouse moved. Not ideal!

This 'throw it away when there are no listeners' behavior is generally done because reactivity frameworks based on 'dirty-flag-checking' have no way to keep the 'dirty flag' up-to-date without potentially creating memory leaks.

signia uses a new lazy reactivity system based on logical clocks instead of 'dirty flags', which allows caching of signal values at all times with no risk of causing memory leaks.

Transactions with rollbacks

Many reactive libraries allow you to make a batch of smaller changes while deferring running effects until after the whole batch has completed. signia supports this while also allowing you to 'bail out' of the batch, resetting all signals to their initial state. This can be useful to avoid corrupting application state after encountering errors.