Svelte

fix: defer batch resolution until earlier intersecting batches have committed

#17162

Closing issue

Pull request

Merged
R
Rich-Harris
Nov 16, 2025, 5:38 PM

This fixes an awkward bug with each blocks containing await, especially keyed each blocks.

If you do array.push(...) multiple times in distinct batches, something weird happens — to the each block, the array looks this...

[1]

...then this...

[undefined, 2]

...then this...

[undefined, undefined, 3]

...and so on. That's because as far as Svelte's reactivity is concerned, what we're really doing is assigning to array[0] then array[1] then array[2]. Those (along with array.length) are each backed by independent sources, which we can rewind individually when we need to 'apply' a batch. When it comes to sources that actually are independent, this is useful, since we apply the changes from batch B to the DOM while we're still waiting for a promise in batch A to resolve. But in this case it's not ideal, because you would expect these changes to accumulate.

In particular, this fails with keyed each blocks because duplicate keys are disallowed (assuming the key function doesn't break on undefined before the duplicate check happens).

This PR fixes it by stacking batches that are interconnected. Specifically, if a later batch has some (but not all) sources in common with an earlier batch, then when we apply the batch we include the sources from the earlier batch, and block it until the earlier batch commits. When the earlier batch commits, it will check to see if doing so unblocks any later batches, and if so process them.

In the course of working on this I realised that SvelteSet and SvelteMap aren't async-ready — will follow up this PR with ones for those.

Fixes

❤️ 1

Info

Merged at Mar 18, 2026, 4:43 PM
Merged by dummdidumm
Assignees None
Reviewers None
Labels None
Milestone None

Pro tip: You can prefix GitHub URLs of issues, PRs or discussions with svcl.dev/ to view them on this page! Also try it on a GitHub release ;)