From 451679a412eec16611d8b6d302638a207397e9f4 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Fri, 17 Jul 2026 20:08:26 +0200 Subject: [PATCH] simplify --- .../src/internal/client/reactivity/batch.js | 48 +++++++++---------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index 310ff69782..a200676aa9 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -103,11 +103,6 @@ var source_stacks = new Set(); let uid = 1; -let effect_version = 1; - -/** @type {WeakMap} */ -const effect_versions = new WeakMap(); - /** * @template T * @param {Set | null} target @@ -270,11 +265,12 @@ export class Batch { merged_into = null; /** - * Async and block effects that ran or were proven clean inside this fork. - * The version is that of the latest real-world execution when the effect was - * validated. Fork executions do not advance it, so forks remain independent. + * Async and block effects that ran or were proven clean inside this fork, + * mapped to whether that validation has since been superseded by a + * real-world run of the effect (see `record_effect`). Runs inside other + * forks don't supersede anything, so forks remain independent. * Lazily initialised for perf reasons - * @type {Map | null} + * @type {Map | null} */ fork_effects = null; @@ -541,26 +537,31 @@ export class Batch { if ((effect.f & (ASYNC | BLOCK_EFFECT)) === 0) return; if (this.is_fork) { - (this.fork_effects ??= new Map()).set(effect, effect_versions.get(effect) ?? 0); + (this.fork_effects ??= new Map()).set(effect, false); } else if (ran) { - effect_versions.set(effect, effect_version++); + // a real-world run supersedes any fork's validation of this effect + for (var batch = first_batch; batch !== null; batch = batch.#next) { + if (batch.is_fork && batch.fork_effects?.has(effect)) { + batch.fork_effects.set(effect, true); + } + } } } claim_fork_effects() { if (this.fork_effects === null) return; - for (const [effect, version] of this.fork_effects) { - if ((effect.f & DESTROYED) !== 0 || version !== (effect_versions.get(effect) ?? 0)) { + for (const [effect, superseded] of this.fork_effects) { + if ((effect.f & DESTROYED) !== 0 || superseded) { this.#dirty_effects?.delete(effect); this.#maybe_dirty_effects?.delete(effect); } } - for (const [effect, version] of this.fork_effects) { + for (const [effect, superseded] of this.fork_effects) { if ((effect.f & DESTROYED) !== 0) continue; - if (version !== (effect_versions.get(effect) ?? 0)) { + if (superseded) { var owner = effect.batch && effect.batch.resolved(); if (owner !== null && owner !== this && owner.linked && !owner.is_fork) { @@ -1154,11 +1155,8 @@ export class Batch { continue; } - for (const [effect, version] of fork.fork_effects) { - if ( - version === (effect_versions.get(effect) ?? 0) || - (effect.f & (DESTROYED | INERT)) !== 0 - ) { + for (const [effect, superseded] of fork.fork_effects) { + if (!superseded || (effect.f & (DESTROYED | INERT)) !== 0) { continue; } @@ -1169,7 +1167,7 @@ export class Batch { // the fork's view of every dependency matches the committed // state — the latest real run is valid for the fork's world // too, so it doesn't need to re-run speculatively - fork.fork_effects.set(effect, effect_versions.get(effect) ?? 0); + fork.fork_effects.set(effect, false); continue; } @@ -1733,20 +1731,18 @@ function mark_committed_reactions(value, batch, marked, status) { var effect = /** @type {Effect} */ (reaction); var owner = effect.batch && effect.batch.resolved(); - var fork_version = batch.fork_effects?.get(effect); - var validated = - fork_version !== undefined && fork_version === (effect_versions.get(effect) ?? 0); + var superseded = batch.fork_effects?.get(effect); var stale = batch.stale_readers?.has(effect) === true || owner?.stale_readers?.has(effect) === true; - if (fork_version === undefined || stale) { + if (superseded === undefined || stale) { if ((reaction.f & DIRTY) === 0) { set_signal_status(reaction, status); } batch.schedule(effect); } else if ( - !validated && + superseded && owner !== null && owner !== batch && owner.linked &&