fix: process batches created in effect and immediately flushed (#18194)

no changeset because the bug this fixes hasn't been released
pull/18196/head
Rich Harris 2 months ago committed by GitHub
parent fcaa8ce723
commit 9950b22869
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -372,12 +372,11 @@ export class Batch {
// once more in that case - most of the time this will just clean up dirty branches.
if (this.#roots.length > 0) {
const batch = (next_batch ??= this);
batches.add(batch);
batch.#roots.push(...this.#roots.filter((r) => !batch.#roots.includes(r)));
}
if (next_batch !== null) {
batches.add(next_batch);
if (DEV) {
for (const source of this.current.keys()) {
/** @type {Set<Source>} */ (source_stacks).add(source);
@ -728,20 +727,14 @@ export class Batch {
static ensure() {
if (current_batch === null) {
const batch = (current_batch = new Batch());
batches.add(batch);
if (!is_processing) {
batches.add(current_batch);
if (!is_flushing_sync) {
queue_micro_task(() => {
if (batch.#started) {
// a flushSync happened in the meantime
return;
}
if (!is_processing && !is_flushing_sync) {
queue_micro_task(() => {
if (!batch.#started) {
batch.flush();
});
}
}
});
}
}

@ -0,0 +1,25 @@
import { tick } from 'svelte';
import { test } from '../../test';
export default test({
async test({ assert, target }) {
await tick();
const [increment, shift] = target.querySelectorAll('button');
increment.click();
await tick();
assert.htmlEqual(target.innerHTML, '<button>clicks: 0</button><button>shift</button> 0');
shift.click();
await tick();
assert.htmlEqual(target.innerHTML, '<button>clicks: 1</button><button>shift</button> 1');
shift.click();
await tick();
assert.htmlEqual(target.innerHTML, '<button>clicks: 2</button><button>shift</button> 2');
}
});

@ -0,0 +1,25 @@
<script lang="ts">
import { flushSync } from 'svelte';
let count = $state(0);
const queue: Array<() => void> = [];
$effect(() => {
if (count === 1) {
count = 2;
flushSync();
}
})
function push(v: number) {
if (v === 0) return v;
return new Promise(r => queue.push(() => r(v)));
}
</script>
<button onclick={() => count += 1}>
clicks: {count}
</button>
<button onclick={() => queue.shift()?.()}>shift</button>
{await push(count)}
Loading…
Cancel
Save