fix: ensure scheduled batch is flushed if not obsolete (#18131)

The logic of checking that the current batch is still the generated one
is flawed. If microtasks align the current batch can be a different
value even if the batch still need to be flushed. This therefore
switches the heuristic to what it actually should express: "has this
batch run already?"

Fixes #18126 (because the batch isn't running, it later runs into the
invariant)
pull/18163/head
Simon H 3 months ago committed by GitHub
parent 4c96b469f8
commit bc82a55647
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: ensure scheduled batch is flushed if not obsolete

@ -716,7 +716,7 @@ export class Batch {
if (!is_flushing_sync) {
queue_micro_task(() => {
if (current_batch !== batch) {
if (!batches.has(batch) || batch.#pending.size > 0) {
// a flushSync happened in the meantime
return;
}

@ -0,0 +1,15 @@
import { tick } from 'svelte';
import { test } from '../../test';
// Ensure that microtask timing doesn't influence whether or not a scheduled batch is flushed.
// Timing can be such that the current_batch is reset before the scheduled flush runs, which
// would cause the flush to skip without the fix.
export default test({
async test({ assert, target }) {
const [btn] = target.querySelectorAll('button');
btn.click();
await tick();
assert.htmlEqual(target.innerHTML, '1 1');
}
});

@ -0,0 +1,18 @@
<script>
let a = $state(0);
let b = $state(0);
</script>
{#if a}
{@const toShow = await a}
{toShow}
{b}
{:else}
<button
onclick={async () => {
a = 1;
await 1;
await 1; // two microtasks needed to get timing right to reproduce the bug
b = 1;
}}>click</button>
{/if}
Loading…
Cancel
Save