From 799b1096faa92a2ec0d0b635bdae7ec608a57323 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Mon, 12 Oct 2026 10:31:38 +0200 Subject: [PATCH] code gold / remove obsolete code (e.g. the "outside reactivity" code is no longer needed because we now mark these deriveds clean if they show the latest value) --- .../src/internal/client/reactivity/batch.js | 42 +++++-------------- .../internal/client/reactivity/deriveds.js | 14 ++----- .../src/internal/client/reactivity/sources.js | 11 +---- 3 files changed, 15 insertions(+), 52 deletions(-) diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index 5fa57e9b6d..c603dd9f25 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -387,22 +387,12 @@ export class Batch { if (this.is_fork) return true; if (this.#blocking_pending === null) return false; - for (const effect of this.#blocking_pending.keys()) { - var e = effect; - var skipped = false; - - while (e.parent !== null) { - if (this.#skipped_branches.has(e)) { - skipped = true; - break; - } - + for (let e of this.#blocking_pending.keys()) { + // pending work inside a skipped branch doesn't block, the branch is going to be destroyed + while (e.parent !== null && !this.#skipped_branches.has(e)) { e = e.parent; } - - if (!skipped) { - return true; - } + if (e.parent === null) return true; } return false; @@ -786,9 +776,6 @@ export class Batch { ? !this.seen_effects?.has(effect) && !this.#dirty_reactions.has(effect) : (flags & (ASYNC | BLOCK_EFFECT)) === 0 || this.seen_effects?.has(effect) ) { - if (this.#dirty_reactions.get(effect) === MAYBE_DIRTY) { - this.#dirty_reactions.delete(effect); - } this.schedule(effect, status); marked = true; } @@ -949,7 +936,7 @@ export class Batch { // so comparing what was read against the real value could not attribute the value to the right // batch, see `async-dont-rebase-new-batch-4`. We only need to look one level deep: `is_dirty` // evaluates the top-most deriveds first, so a dependency derived that was itself not the latest - // value was not written to the real world, and differs from our value for it. + // value was not written to the real world, which the check above already catches. for (let batch = this.next; batch !== null && is_latest_value; batch = batch.next) { if (batch.is_fork) continue; @@ -957,10 +944,8 @@ export class Batch { if ( batch.current.has(source) || ((source.f & DERIVED) !== 0 && - /** @type {Derived} */ (source).deps?.some( - (d) => - /** @type {Batch} */ (batch).current.has(d) || - (this.current.has(d) && /** @type {{ v: any }} */ (this.current.get(d)).v !== d.v) + /** @type {Derived} */ (source).deps?.some((d) => + /** @type {Batch} */ (batch).current.has(d) )) ) { is_latest_value = false; @@ -1018,7 +1003,9 @@ export class Batch { ) { if (current !== undefined) this.current.set(source, current); } else { - this.queue_revalidation(source); + queue_micro_task(() => { + if (this.linked && this.mark(source, DIRTY)) this.flush(); + }); } } } @@ -1042,15 +1029,6 @@ export class Batch { }); } - /** @param {Value} source */ - queue_revalidation(source) { - queue_micro_task(() => { - if (this.linked && this.mark(source, DIRTY)) { - this.flush(); - } - }); - } - /** * Activate batch - could be merged into another batch in the meantime, * in which case that other batch becomes the active batch. diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js index cd8fe6eb45..df475312f3 100644 --- a/packages/svelte/src/internal/client/reactivity/deriveds.js +++ b/packages/svelte/src/internal/client/reactivity/deriveds.js @@ -195,8 +195,7 @@ export function async_derived(fn, label, location) { // If an earlier batch has a run of this async effect in flight, the two batches // are related and this one has to wait for (i.e. merge into) the earlier one. // Same for forks, though the other way around (the fork has to wait for this batch). - let other = first_batch; - while (other) { + for (let other = first_batch; other !== null; other = other.next) { if (other !== batch && other.async_deriveds.has(effect)) { if (other.id < batch.id) { batch.dependent.add(other); @@ -204,7 +203,6 @@ export function async_derived(fn, label, location) { other.dependent.add(batch); } } - other = other.next; } if (should_suspend) { @@ -425,9 +423,7 @@ export function execute_derived(derived) { */ export function update_derived(derived) { var value = execute_derived(derived); - var d = own_value(derived); - - if (d === derived ? !derived.equals(value) : !derived.equals.call(d, value)) { + if (!derived.equals.call(own_value(derived), value)) { if (current_batch !== null || previous_batch !== null) { // `capture` decides whether the underlying value is updated (it isn't in a fork, // or if a later batch holds a newer value) and records it in the batch either way. @@ -460,11 +456,7 @@ export function update_derived(derived) { // During time travelling, keep stale results batch-local. A result computed // from the latest inputs can be marked globally clean, even if it is unchanged // and its write version therefore remains below its dependencies' versions. - if ( - batch_values !== null || - // "read outside of reactivity", e.g. in an event handler - (!current_batch && first_batch?.next) - ) { + if (batch_values !== null) { // only cache the value if we're in a tracking context, otherwise we won't // clear the cache in `mark_reactions` when dependencies are updated if (effect_tracking() || current_batch?.is_fork) { diff --git a/packages/svelte/src/internal/client/reactivity/sources.js b/packages/svelte/src/internal/client/reactivity/sources.js index aa7a94016f..467cda6fcd 100644 --- a/packages/svelte/src/internal/client/reactivity/sources.js +++ b/packages/svelte/src/internal/client/reactivity/sources.js @@ -38,7 +38,6 @@ import { schedule_effect, legacy_updates, current_batch, - first_batch, own_value } from './batch.js'; import { proxy } from '../proxy.js'; @@ -190,9 +189,7 @@ var count_deps = 0; * @returns {V} */ export function internal_set(source, value, updated_during_traversal = null) { - var s = own_value(source); - - if (s === source ? !source.equals(value) : !source.equals.call(s, value)) { + if (!source.equals.call(own_value(source), value)) { if (is_destroying_effect) { old_values.set(source, value); } else if (!old_values.has(source)) { @@ -211,11 +208,7 @@ export function internal_set(source, value, updated_during_traversal = null) { // During time traveling we don't want to reset the status so that // traversal of the graph in the other batches still happens - if ( - batch_values === null && - // could also be "read outside of reactivity", e.g. in an event handler - !first_batch?.next - ) { + if (batch_values === null) { update_derived_status(derived); } }