From 59345a2f582db2efebdc52e5db4eddf9979791b0 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Tue, 14 Jul 2026 23:47:44 +0200 Subject: [PATCH] code golf --- .../src/internal/client/reactivity/batch.js | 145 ++++++++---------- .../internal/client/reactivity/deriveds.js | 18 +-- .../src/internal/client/reactivity/sources.js | 6 +- 3 files changed, 73 insertions(+), 96 deletions(-) diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index 1836b09d5b..1526e0c464 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -115,6 +115,25 @@ var source_stacks = new Set(); let uid = 1; +/** + * @template T + * @param {Set | null} target + * @param {Set | null} source + * @returns {Set | null} + */ +function transfer_set(target, source) { + if (source === null || source.size === 0) return target; + + target ??= new Set(); + + for (const value of source) { + target.add(value); + } + + source.clear(); + return target; +} + export class Batch { id = uid++; @@ -284,7 +303,7 @@ export class Batch { } #is_deferred() { - if (this.waiting !== null && this.waiting.batches.size > 0) return true; + if (this.waiting !== null) return true; if (this.is_fork) return true; if (this.#blocking_pending === null) return false; @@ -391,34 +410,35 @@ export class Batch { if (waiter === null || !(waiter = waiter.#resolved()).linked) return; - waiter.waiting?.batches.delete(this); + var waiting = /** @type {{ batches: Set, reactions: Map }} */ ( + waiter.waiting + ); + waiting.batches.delete(this); - if (waiter.waiting !== null) { - for (const [reaction, owner] of waiter.waiting.reactions) { - if (owner !== this) continue; + for (const [reaction, owner] of waiting.reactions) { + if (owner !== this) continue; - waiter.waiting.reactions.delete(reaction); - if ((reaction.f & DESTROYED) !== 0) continue; + waiting.reactions.delete(reaction); + if ((reaction.f & DESTROYED) !== 0) continue; - reaction.batch = waiter; + reaction.batch = waiter; - if ((reaction.f & DERIVED) !== 0 && (reaction.f & DIRTY) === 0) { - set_signal_status(reaction, MAYBE_DIRTY); - } else if ((reaction.f & DERIVED) === 0) { - var effect = /** @type {Effect} */ (reaction); - - if (waiter.#dirty_effects?.delete(effect)) { - set_signal_status(effect, DIRTY); - waiter.schedule(effect); - } else if (waiter.#maybe_dirty_effects?.delete(effect)) { - set_signal_status(effect, MAYBE_DIRTY); - waiter.schedule(effect); - } + if ((reaction.f & DERIVED) !== 0 && (reaction.f & DIRTY) === 0) { + set_signal_status(reaction, MAYBE_DIRTY); + } else if ((reaction.f & DERIVED) === 0) { + var effect = /** @type {Effect} */ (reaction); + + if (waiter.#dirty_effects?.delete(effect)) { + set_signal_status(effect, DIRTY); + waiter.schedule(effect); + } else if (waiter.#maybe_dirty_effects?.delete(effect)) { + set_signal_status(effect, MAYBE_DIRTY); + waiter.schedule(effect); } } } - if (waiter.waiting !== null && waiter.waiting.batches.size > 0) return; + if (waiting.batches.size > 0) return; waiter.waiting = null; var released = /** @type {Batch} */ (waiter); @@ -426,7 +446,7 @@ export class Batch { queue_micro_task(() => { var batch = released.#resolved(); - if (batch.linked && (batch.waiting === null || batch.waiting.batches.size === 0)) { + if (batch.linked && batch.waiting === null) { batch.flush(); } }); @@ -479,7 +499,7 @@ export class Batch { } if (owner !== null && owner !== this && owner.linked && !owner.is_fork) { - if (owner.waiting !== null && owner.waiting.batches.size > 0) { + if (owner.waiting !== null) { this.#merge(owner); reaction.batch = this; return false; @@ -595,14 +615,8 @@ export class Batch { } other.#scheduled = []; - if (other.stale_readers !== null) { - this.stale_readers ??= new Set(); - - for (const reader of other.stale_readers) { - this.stale_readers.add(reader); - } - other.stale_readers = null; - } + this.stale_readers = transfer_set(this.stale_readers, other.stale_readers); + other.stale_readers = null; if (other.waiting !== null) { this.waiting ??= { batches: new Set(), reactions: new Map() }; @@ -687,7 +701,7 @@ export class Batch { #process() { this.#started = true; - if (this.waiting !== null && this.waiting.batches.size > 0) return; + if (this.waiting !== null) return; // this batch may be re-processed (e.g. when effects are scheduled during // its effect-flush phase), in which case async work could still be @@ -830,11 +844,8 @@ export class Batch { this.#commit(); // #commit may have scheduled stale readers into a new batch - if (next_batch === null) { - next_batch = /** @type {Batch | null} */ (/** @type {unknown} */ (current_batch)); - } else { - current_batch = next_batch; - } + next_batch ??= /** @type {Batch | null} */ (/** @type {unknown} */ (current_batch)); + current_batch = next_batch; } } @@ -1050,18 +1061,15 @@ export class Batch { * @param {Effect} effect */ increment(blocking, effect) { - if (this.merged_into !== null) { - this.#resolved().increment(blocking, effect); - return; - } + var batch = this.merged_into === null ? this : this.#resolved(); - this.#pending += 1; + batch.#pending += 1; if (blocking) { - this.#blocking_pending ??= new Map(); + batch.#blocking_pending ??= new Map(); - let blocking_pending_count = this.#blocking_pending.get(effect) ?? 0; - this.#blocking_pending.set(effect, blocking_pending_count + 1); + let blocking_pending_count = batch.#blocking_pending.get(effect) ?? 0; + batch.#blocking_pending.set(effect, blocking_pending_count + 1); } } @@ -1070,31 +1078,28 @@ export class Batch { * @param {Effect} effect */ decrement(blocking, effect) { - if (this.merged_into !== null) { - this.#resolved().decrement(blocking, effect); - return; - } + var batch = this.merged_into === null ? this : this.#resolved(); - this.#pending -= 1; + batch.#pending -= 1; - if (blocking && this.#blocking_pending !== null) { - let blocking_pending_count = this.#blocking_pending.get(effect) ?? 0; + if (blocking && batch.#blocking_pending !== null) { + let blocking_pending_count = batch.#blocking_pending.get(effect) ?? 0; if (blocking_pending_count === 1) { - this.#blocking_pending.delete(effect); + batch.#blocking_pending.delete(effect); } else { - this.#blocking_pending.set(effect, blocking_pending_count - 1); + batch.#blocking_pending.set(effect, blocking_pending_count - 1); } } - if (this.#decrement_queued) return; - this.#decrement_queued = true; + if (batch.#decrement_queued) return; + batch.#decrement_queued = true; queue_micro_task(() => { - this.#decrement_queued = false; + batch.#decrement_queued = false; - if (this.linked) { - this.flush(); + if (batch.linked) { + batch.flush(); } }); } @@ -1105,26 +1110,8 @@ export class Batch { */ transfer_effects(dirty_effects, maybe_dirty_effects) { var batch = this.#resolved(); - - if (dirty_effects !== null && dirty_effects.size > 0) { - batch.#dirty_effects ??= new Set(); - - for (const e of dirty_effects) { - batch.#dirty_effects.add(e); - } - - dirty_effects.clear(); - } - - if (maybe_dirty_effects !== null && maybe_dirty_effects.size > 0) { - batch.#maybe_dirty_effects ??= new Set(); - - for (const e of maybe_dirty_effects) { - batch.#maybe_dirty_effects.add(e); - } - - maybe_dirty_effects.clear(); - } + batch.#dirty_effects = transfer_set(batch.#dirty_effects, dirty_effects); + batch.#maybe_dirty_effects = transfer_set(batch.#maybe_dirty_effects, maybe_dirty_effects); } /** @param {(batch: Batch) => void} fn */ diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js index a762cfaf34..8f10c3a864 100644 --- a/packages/svelte/src/internal/client/reactivity/deriveds.js +++ b/packages/svelte/src/internal/client/reactivity/deriveds.js @@ -11,7 +11,6 @@ import { ASYNC, WAS_MARKED, DESTROYED, - CLEAN, REACTION_RAN, INERT } from '#client/constants'; @@ -40,7 +39,7 @@ import { UNINITIALIZED } from '../../../constants.js'; import { batch_values, current_batch, previous_batch } from './batch.js'; import { increment_pending, unset_context } from './async.js'; import { deferred, includes, noop } from '../../shared/utils.js'; -import { set_signal_status, update_derived_status } from './status.js'; +import { update_derived_status } from './status.js'; /** * This allows us to track 'reactivity loss' that occurs when signals @@ -421,21 +420,14 @@ export function update_derived(derived) { } derived.v = value; - - // deriveds without dependencies should never be recomputed - if (derived.deps === null) { - set_signal_status(derived, CLEAN); - return; - } } // don't mark derived clean if we're reading it inside a - // cleanup function, or it will cache a stale value - if (is_destroying_effect) { - return; + // cleanup function, or it will cache a stale value. deriveds + // without dependencies can always be marked clean + if (!is_destroying_effect || derived.deps === null) { + update_derived_status(derived); } - - update_derived_status(derived); } /** diff --git a/packages/svelte/src/internal/client/reactivity/sources.js b/packages/svelte/src/internal/client/reactivity/sources.js index 227086062f..f733eab3f7 100644 --- a/packages/svelte/src/internal/client/reactivity/sources.js +++ b/packages/svelte/src/internal/client/reactivity/sources.js @@ -369,10 +369,8 @@ export function mark_reactions(signal, status, updated_during_traversal) { current_batch?.claim(derived); // invalidate any world-local memoized values - if (batch_values !== null) { - batch_values.delete(derived); - current_batch?.fork_values?.delete(derived); - } + batch_values?.delete(derived); + current_batch?.fork_values?.delete(derived); if ((flags & WAS_MARKED) === 0) { // Only connected deriveds being executed outside the update cycle can be reliably unmarked right away