fix: don't deactivate other batches (#17132)

There's a possibility of a race condition where `batch.deactivate()` is called while `current_batch !== batch`, and so it would deactivate another batch, which can lead to zombie batches that are never flushed, subsequently leading to wrong `batch_values`. This fixes that by checking if the current batch is the own batch.

Fixes #17109
pull/17135/head
Simon H 3 days ago committed by GitHub
parent 554202ecf4
commit 14b0926008
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: don't deactivate other batches

@ -299,6 +299,10 @@ export class Batch {
} }
deactivate() { deactivate() {
// If we're not the current batch, don't deactivate,
// else we could create zombie batches that are never flushed
if (current_batch !== this) return;
current_batch = null; current_batch = null;
batch_values = null; batch_values = null;
} }

@ -0,0 +1,14 @@
<script lang="ts">
let { ref } = $props();
let tick = $state(0);
let ref_exists = $state(true);
$effect(() => {
tick;
ref_exists = ref !== null;
});
</script>
<p>{ref_exists}</p>
<button onclick={() => tick++}>check</button>

@ -0,0 +1,23 @@
import { tick } from 'svelte';
import { test } from '../../test';
// This test regresses against batches deactivating other batches than themselves
export default test({
async test({ assert, target }) {
await tick(); // settle initial await
const button = target.querySelector('button');
button?.click();
await tick();
assert.htmlEqual(
target.innerHTML,
`
<div>div</div>
<p>true</p>
<button>check</button>
<p></p>
`
);
}
});

@ -0,0 +1,15 @@
<script>
import Component from "./Component.svelte";
let ref = $state(null);
let foo = $derived(await 1);
</script>
<div bind:this={ref}>div</div>
<Component {ref} />
{#if foo}
<p></p>
{/if}
Loading…
Cancel
Save