From 276a4c06d35c851ff2c7570111b81501e971c272 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Thu, 27 Aug 2026 14:46:22 +0200 Subject: [PATCH] remove stale_readers, it's obsolete now --- .../src/internal/client/reactivity/batch.js | 67 +------------------ .../svelte/src/internal/client/runtime.js | 23 +------ 2 files changed, 4 insertions(+), 86 deletions(-) diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index a76509358c..aea176420a 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -330,16 +330,6 @@ export class Batch { */ fork_effects = null; - /** - * Reactions that observed the pre-write world of this batch via its active - * overlay while it was pending, mapped to the values they saw. When this - * batch commits, readers whose observed values differ from the committed - * ones re-run with the real values. - * Lazily initialised for perf reasons - * @type {Map> | null} - */ - stale_readers = null; - /** * `true` while this batch is flushing its effects and is provably terminal — * solitary, with no pending async work and nothing scheduled. Such a batch @@ -720,14 +710,6 @@ export class Batch { this.#scheduled.push(...other.#scheduled); other.#scheduled = []; - // TODO could a newer value have been observed by this and other is older? - this.stale_readers = transfer_map( - this.stale_readers, - other.stale_readers, - (observed, seen) => /** @type {Map} */ (transfer_map(observed, seen)) - ); - other.stale_readers = null; - if (other.waiting !== null) { var waiting = (this.waiting ??= { batches: new Set(), reactions: new Map() }); @@ -1207,51 +1189,6 @@ export class Batch { }); } } - - if (this.stale_readers === null) return; - - var readers = this.stale_readers; - this.stale_readers = null; - - var batch = Batch.ensure(); - - for (const [reader, seen] of readers) { - var flags = reader.f; - - if ((flags & (DESTROYED | INERT | DIRTY)) !== 0) continue; - - // Only re-run readers that are actually affected by the commit: a - // reader observed specific values through this batch's overlay. If - // each of those matches the committed value (the write was reverted, - // or a derived recomputed to an equal value), or the reader no - // longer depends on it, the reader's world didn't change - var status = CLEAN; - - for (const [signal, value] of seen) { - if (reader.deps === null || !includes.call(reader.deps, signal)) continue; - - if ((signal.f & (DIRTY | MAYBE_DIRTY)) !== 0) { - // a derived that hasn't been revalidated with the committed - // values yet — the reader's own validation will recompute it - // (with equality applying) via `is_dirty` - status = MAYBE_DIRTY; - } else if (signal.v !== value) { - status = DIRTY; - break; - } - } - - if (status === CLEAN) continue; - - set_signal_status(reader, status); - - if ((flags & DERIVED) !== 0) { - // invalidate anything that depends on the derived - mark_reactions(/** @type {Derived} */ (reader), MAYBE_DIRTY, null); - } else { - batch.schedule(/** @type {Effect} */ (reader)); - } - } } /** @@ -1749,10 +1686,8 @@ function mark_committed_reactions(value, batch, marked, status) { var owner = effect.batch && effect.batch.resolved(); var superseded = batch.fork_effects?.get(effect); - var stale = - batch.stale_readers?.has(effect) === true || owner?.stale_readers?.has(effect) === true; - if (superseded === undefined || stale) { + if (superseded === undefined) { if ((reaction.f & DIRTY) === 0) { set_signal_status(reaction, status); } diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index fdea636ef0..af89ead9aa 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -725,7 +725,7 @@ export function get(signal) { active_batch.values !== null && (owner = claimed_by_other(derived)) !== null ) { - if (is_unseen_read(derived, owner, first_read) && entangle(derived)) { + if (is_unseen_read(derived, first_read) && entangle(derived)) { // a read with no history can entangle the two batches instead, so // that they commit together — the derived is now part of this // batch's world and behaves normally (below) @@ -794,13 +794,6 @@ export function get(signal) { } else if (!untracking) { override_owner = override_owner.resolved(); - var seen = override_owner.stale_readers?.get(active_reaction); - - // a reader keeps seeing the value it first observed while the owner is pending - if (seen !== undefined && seen.has(signal)) { - return seen.get(signal); - } - var override_value = override[0]; if ( @@ -829,14 +822,6 @@ export function get(signal) { override_value = signal.v; } - var readers = (override_owner.stale_readers ??= new Map()); - - if (seen === undefined) { - readers.set(active_reaction, (seen = new Map())); - } - - seen.set(signal, override_value); - return override_value; } } @@ -858,11 +843,10 @@ export function get(signal) { * nor observed a value for it while the owner batch was pending. (Reads outside * a reaction never have history.) * @param {Value} signal - * @param {Batch} owner * @param {boolean} first_read whether a post-`await` read just added `signal` to the reaction's deps * @returns {boolean} */ -function is_unseen_read(signal, owner, first_read) { +function is_unseen_read(signal, first_read) { if (active_reaction === null) return true; if (untracking) return false; @@ -874,8 +858,7 @@ function is_unseen_read(signal, owner, first_read) { return false; } - var seen = owner.resolved().stale_readers?.get(active_reaction); - return seen === undefined || !seen.has(signal); + return true; } /**