mirror of https://github.com/sveltejs/svelte
Without it, a reaction that reads N stale values queues N re-runs, each of which flushes the later batch — quadratic work (seconds for a 2000-item each block). The new test is a timing guard: the output is identical either way.async-another-try-pt-1-prune
parent
4fef105eaa
commit
7a0b430ec5
@ -0,0 +1,39 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
const buttons = '<button>show</button><button>items</button><button>shift</button>';
|
||||
/** @param {number} offset */
|
||||
const list = (offset) => Array.from({ length: 2000 }, (_, i) => `${i + offset},`).join('');
|
||||
|
||||
// When the branch is created in B1, the each block reads all 2000 items, each of which B2 holds
|
||||
// a newer value of. The each block must be scheduled to re-run in B2 once, not once per stale
|
||||
// value — otherwise B2 is flushed 2000 times (each flush being O(size of B2)), which takes seconds
|
||||
export default test({
|
||||
mode: ['client'],
|
||||
async test({ assert, target }) {
|
||||
await tick();
|
||||
const [show, items, shift] = target.querySelectorAll('button');
|
||||
|
||||
// B1: show = true -> pending
|
||||
show.click();
|
||||
await tick();
|
||||
|
||||
// B2: increment all items -> pending
|
||||
items.click();
|
||||
await tick();
|
||||
|
||||
// B1 resolves -> the branch is created, reading 2000 values that are stale relative to B2
|
||||
const start = performance.now();
|
||||
shift.click();
|
||||
await tick();
|
||||
const duration = performance.now() - start;
|
||||
|
||||
assert.ok(duration < 1000, `took ${duration}ms`);
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>0</p><div>${list(0)}</div>`);
|
||||
|
||||
// B2 resolves
|
||||
shift.click();
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, `${buttons}<p>1</p><div>${list(1)}</div>`);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
let show = $state(false);
|
||||
let items = $state(Array.from({ length: 2000 }, (_, i) => i));
|
||||
|
||||
const deferred = [];
|
||||
|
||||
function delay(v) {
|
||||
if (!v) return v;
|
||||
return new Promise((resolve) => deferred.push(() => resolve(v)));
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={() => (show = true)}>show</button>
|
||||
<button onclick={() => items.forEach((_, i) => items[i]++)}>items</button>
|
||||
<button onclick={() => deferred.shift()?.()}>shift</button>
|
||||
|
||||
<p>{await delay(items[0])}</p>
|
||||
|
||||
{#if await delay(show)}
|
||||
<div>
|
||||
{#each items as item}{item},{/each}
|
||||
</div>
|
||||
{/if}
|
||||
Loading…
Reference in new issue