From 62fafd63abd8c2afddeff5d54a4ade57fef94610 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Sun, 20 Sep 2026 22:36:23 +0200 Subject: [PATCH] align --- .../src/internal/client/reactivity/batch.js | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index 9eccd5e385..602028e658 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -654,16 +654,7 @@ export class Batch { while (batch !== null) { if (!batch.is_fork) { - // if the batches are connected, break - // for (const [value, [, is_derived]] of this.current) { - // if (batch.current.has(value) && !is_derived) { - // return batch; - // } - // } if (this.dependent.has(batch)) { - // TODO what if there's a fork between the chosen batch and the current one, - // then the fork commits (but is still pending), then the chosen batch - // finishes - then we would apply UI update of B1+B3 before B2. return batch; } } @@ -738,9 +729,6 @@ export class Batch { this.previous.set(source, batch.previous.get(source)); } - if (this.current.get(source)?.[0] !== value[0]) { - // this.mark(source, DIRTY); - } this.current.set(source, value); } @@ -768,9 +756,6 @@ export class Batch { for (const s of batch.unskipped_branches.keys()) { const v = this.#skipped_branches.get(s); - // TODO i do wonder at this point if it's less code / easier / more robust to do what mark() below does - // instead and just rerun all the block effects. Though it will certainly overrun some blocks, potentially - // with bad consequences for e.g. each blocks (could generate a new array etc etc). if (v) { v.d = v.d.filter((e) => !batch.async_deriveds.has(e)); v.m = v.m.filter((e) => !batch.async_deriveds.has(e)); @@ -782,7 +767,6 @@ export class Batch { // This can happen when batch Y merged into X and Y has a pending boundary and therefore still-pending async deriveds inside. batch.async_deriveds.clear(); - // Mark is not guaranteed not touch these, so we transfer them this.transfer_effects(batch.#dirty_effects, batch.maybe_dirty_effects, batch.#dirty_deriveds); this.oncommit(() => batch.discard()); @@ -858,32 +842,7 @@ export class Batch { } if (batch.is_fork && is_latest_value) { - const current = batch.current.get(source); - batch.current.delete(source); - - if (![...batch.current.values()].some((v) => !v[1])) { - batch.discard(); - } else { - if (current) batch.current.set(source, current); - if ( - !is_derived && - (!current || current[0] !== value) && - ((source.f & ASYNC) === 0 || - !depends_on( - source.e, - [...batch.current.keys()].filter((s) => !this.current.has(s)), - new Map() - )) - ) { - batch.current.delete(source); - const b = batch; - queue_micro_task(() => { - if (b.mark(source, DIRTY)) { - b.flush(); - } - }); - } - } + this.notify_fork(batch, source, is_derived, value); } batch = batch.next; } @@ -930,6 +889,43 @@ export class Batch { // } } + /** + * Tell a fork batch that a source has been updated. Will delete that source from the fork, + * discarding it if it has no other sources left, and rerunning it else with the new value. + * @param {Batch} batch A fork + * @param {Source} source + * @param {boolean} is_derived + * @param {any} value + */ + notify_fork(batch, source, is_derived, value) { + const current = batch.current.get(source); + batch.current.delete(source); + + if (![...batch.current.values()].some((v) => !v[1])) { + batch.discard(); + } else { + if (current) batch.current.set(source, current); + if ( + !is_derived && + (!current || current[0] !== value) && + ((source.f & ASYNC) === 0 || + !depends_on( + source.e, + [...batch.current.keys()].filter((s) => !this.current.has(s)), + new Map() + )) + ) { + batch.current.delete(source); + const b = batch; + queue_micro_task(() => { + if (b.mark(source, DIRTY)) { + b.flush(); + } + }); + } + } + } + /** * Activate batch - could be merged into another batch in the meantime, * in which case that other batch becomes the active batch. @@ -1802,14 +1798,18 @@ export function fork(fn) { batch.flush(); // Other forks might need to rerun now with the updated state. - // TODO reuse batch.capture() logic here (delete values from fork and possibly discard, depend on other batches etc) (maybe we can just call it?) let next_batch = batch.next; while (next_batch) { - for (const [source, [, is_derived]] of batch.current) { - if (!is_derived && !next_batch.current.has(source)) { - if (next_batch.mark(source, DIRTY)) { - next_batch.flush(); - } + for (const [source, [value, is_derived]] of batch.current) { + if (next_batch.current.has(source)) { + batch.notify_fork(next_batch, source, is_derived, value); + } else if (!is_derived) { + const b = next_batch; + queue_micro_task(() => { + if (b.mark(source, DIRTY)) { + b.flush(); + } + }); } } next_batch = next_batch.next;