Post

Preact Signals just got a huge performance boost: Signals rendered as text/props & effects only "pull" as fast as needed for rendering. Since computeds run as-needed, they now only re-run as often as their downstream DOM output can be painted. H/t to @jovidecroock.com for making this happen.

34 reposts232 likes

To be clear, Svelte 5 used to have something like this with our scheduling but we had to back out of it due to some issues that surfaced due to the sequencing of some things not happening soon enough. However, we're going to look into re-enabling some form of it again in the future.

Looking at back why we reverted it, it was because of things like the `disabled` attribute. If you don't apply that in a microtask, then the next event coming in will read the stale value and do the incorrect thing. Flushing template effects on events just gets us back to where we started.

In the video, a signal containing the mouse coords is used to compute thousands of positions that are applied to thousands of elements as CSS in an Effect. In 1.x, when the rate of input exceeds screen refresh rate, computations run more often than their results can be painted. In 2.x, they don't.

The really awesome thing is, this effectively brings the value of scheduling to signals without any of the headaches normally associated with scheduling: Because it's not possible to bog the graph down by computing state for outdated frames, it's able to begin computing on every frame instantly.

This is possible because Preact Signals uses a two-phase design: changing a signal _notifies_ its dependencies that they need to recompute (top-down), but recomputation is only performed when each dependency's value is accessed (bottom-up). All we have to do is intelligently schedule the leaf reads!