Skip to content

Conversation

Rich-Harris
Copy link
Member

@Rich-Harris Rich-Harris commented Aug 14, 2025

We prune effects that have no dependencies and no children. But in many cases we can be more aggressive — if we have an {#if browser} block, for example, browser is never going to change and so it's useless to add the block effect to the effect tree, other than to indirectly add its children.

Another example is an attachment that doesn't read anything reactive (i.e. {@attach (node) => {...}}, which is probably 99% of cases). Today, if you use log_effect_tree to look at the effect tree immediately after mounting this component...

<input
  value='hello'
  {@attach (node) => node.select()}
/>

{#if true}
  <p>it's true</p>
{/if}

...you see this:

image

After this PR, it looks like this — notice the intermediate block effects have been replaced by their children:

image

This means less memory pressure (effects can be garbage collected), and faster traversal. Though admittedly it's hard to see a clear win in the benchmark results:

Results of `pnpm bench:compare`
sbench_create_signals
  time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  261.31ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 279.61ms
  gc_time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   56.63ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 63.94ms
sbench_create_0to1
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 6.99ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼     5.60ms
sbench_create_1to1
  time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 20.06ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 20.07ms
  gc_time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 2.02ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 2.04ms
sbench_create_2to1
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 17.44ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 17.35ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 2.07ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  1.93ms
sbench_create_4to1
  time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 16.07ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 16.07ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 2.03ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  1.96ms
sbench_create_1000to1
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 14.35ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 14.25ms
  gc_time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.99ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 2.01ms
sbench_create_1to2
  time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 9.09ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 9.15ms
sbench_create_1to4
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 7.75ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 7.66ms
sbench_create_1to8
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 6.78ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  6.59ms
sbench_create_1to1000
  time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 7.35ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 7.40ms
  gc_time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 0.21ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 0.21ms
kairo_avoidable_owned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 511.49ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 505.36ms
  gc_time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼    17.24ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 19.71ms
kairo_avoidable_unowned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 600.08ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 594.71ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 19.25ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 19.15ms
kairo_broad_owned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 489.90ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 489.56ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.86ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   1.71ms
kairo_broad_unowned
  time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 482.70ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 484.67ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.90ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  1.84ms
kairo_deep_owned
  time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 209.22ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 210.22ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.21ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   1.10ms
kairo_deep_unowned
  time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 898.47ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 899.15ms
  gc_time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.09ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.09ms
kairo_diamond_owned
  time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 421.64ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 423.07ms
  gc_time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  9.04ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 9.35ms
kairo_diamond_unowned
  time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 490.68ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 499.09ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 9.36ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 9.15ms
kairo_triangle_owned
  time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 134.03ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 134.58ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.68ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  1.61ms
kairo_triangle_unowned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 230.25ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 230.06ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.85ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  1.72ms
kairo_mux_owned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 324.89ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 324.79ms
  gc_time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  1.43ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.48ms
kairo_mux_unowned
  time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 452.41ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 458.13ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.43ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.42ms
kairo_repeated_owned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 76.93ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 76.88ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.38ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  1.31ms
kairo_repeated_unowned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 74.53ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 74.47ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.38ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  1.33ms
kairo_unstable_owned
  time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 116.03ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 116.20ms
  gc_time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  1.21ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.26ms
kairo_unstable_unowned
  time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 133.59ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 134.06ms
  gc_time: fastest is a (better-effect-pruning)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.24ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.27ms
mol_bench_owned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 308.95ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 304.83ms
mol_bench_unowned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 324.30ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 322.13ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 0.42ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   0.37ms

I suspect this is a case where a benchmark fails to capture the reality of a large application.

Before submitting the PR, please make sure you do the following

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • Prefix your PR title with feat:, fix:, chore:, or docs:.
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.
  • If this PR changes code within packages/svelte/src, add a changeset (npx changeset).

Tests and linting

  • Run the tests with pnpm test and lint the project with pnpm lint

Copy link

changeset-bot bot commented Aug 14, 2025

🦋 Changeset detected

Latest commit: 514699a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
svelte Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Contributor

Playground

pnpm add https://pkg.pr.new/svelte@16625

@Rich-Harris Rich-Harris marked this pull request as ready for review August 15, 2025 00:14
@Ocean-OS Ocean-OS merged commit d3cb148 into main Aug 23, 2025
16 checks passed
@Ocean-OS Ocean-OS deleted the better-effect-pruning branch August 23, 2025 20:29
@github-actions github-actions bot mentioned this pull request Aug 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants