From 957330c89c93dd7faa14c4880b4ba5c0696c293e Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Thu, 24 Sep 2026 00:18:25 +0200 Subject: [PATCH] feedback --- .../src/internal/client/reactivity/batch.js | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index b36fb826b1..ce69a4ef8c 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -124,7 +124,11 @@ export class Batch { linked = false; - /** @type {Batch | null} */ + /** + * The batch into which this batch has been merged (because it finished and + * depended on a prior batch that needs to resolve first), if any. + * @type {Batch | null} + */ merged_into = null; /** @@ -161,23 +165,27 @@ export class Batch { next = null; /** - * Batches that depend on this batch. - * Lazily initialized for performance reasons. * @type {Set | null} */ #dependent = null; + /** + * Batches that depend on this batch. + * Lazily initialized for performance reasons. + */ get dependent() { return (this.#dependent ??= new Set()); } /** - * All started async work in this batch. - * Lazily initialized for performance reasons. * @type {Map>> | null} */ #async_deriveds = null; + /** + * All started async work in this batch. + * Lazily initialized for performance reasons. + */ get async_deriveds() { return (this.#async_deriveds ??= new Map()); } @@ -266,13 +274,15 @@ export class Batch { #skipped_branches = new Map(); /** - * Inverse of #skipped_branches which we need to tell prior batches to unskip them when committing. - * `true` indicates that this branch is new to the eyes of this fork but was already created before. - * Lazily initialized for performance reasons. * @type {Map | null} */ #unskipped_branches = null; + /** + * Inverse of #skipped_branches which we need to tell prior batches to unskip them when committing. + * `true` indicates that this branch is new to the eyes of this fork but was already created before. + * Lazily initialized for performance reasons. + */ get unskipped_branches() { return (this.#unskipped_branches ??= new Map()); } @@ -589,7 +599,8 @@ export class Batch { } else if (first_time) { // We're seeing a fork-only branch for the first time in another fork. We need to traverse // all effects inside it (they're all marked MAYBE_DIRTY). This is necessary because - // dependencies of the effects inside could've updated since the last time this branch ran. + // dependencies of the effects inside could've updated in the real world since the last time this branch ran. + // TODO this can overfire, maybe there's a way to detect which sources actually changed. this.unskipped_branches.set(effect, false); all_dirty ??= effect; if (effect.f & CLEAN) effect.f ^= CLEAN; @@ -888,7 +899,7 @@ export class Batch { const current = batch.current.get(source); batch.current.delete(source); - if (![...batch.current.values()].some((value) => !value.is_derived)) { + if ([...batch.current.values()].every((value) => !value.is_derived)) { // The real world has overtaken every write of this fork, so it is obsolete. Discard it // right away (its speculative branches must not be adopted by anyone), and empty // `current` so that `commit()` can tell this apart from a user-initiated discard @@ -1084,6 +1095,13 @@ export class Batch { return current_batch; } + /** + * - `include_earlier` false: batch_values etc should see the latest values up until itself, + * i.e. including latest value of all earlier batches; previous values only of later batches. + * - `include_earlier` true: the "world view" of batch_values is current values are only of this batch, + * previous values of all other batches. + * @param {boolean} include_earlier + */ apply(include_earlier = false) { if (!async_mode_flag || (!this.is_fork && this.prev === null && this.next === null)) { batch_values = null;