mirror of https://github.com/sveltejs/svelte
Marking the derived clean while other batches are in flight hides changes they haven't seen yet.async-another-try-pt-1-prune
parent
fa16f59447
commit
336d1ef608
@ -0,0 +1,39 @@
|
|||||||
|
import { tick } from 'svelte';
|
||||||
|
import { test } from '../../test';
|
||||||
|
|
||||||
|
const buttons =
|
||||||
|
'<button>s</button><button>u</button><button>d</button><button>resolve a</button><button>resolve b</button><button>resolve c</button>';
|
||||||
|
|
||||||
|
export default test({
|
||||||
|
mode: ['client'],
|
||||||
|
async test({ assert, target, logs }) {
|
||||||
|
await tick();
|
||||||
|
const [s, u, d, resolve_a, resolve_b, resolve_c] = target.querySelectorAll('button');
|
||||||
|
|
||||||
|
// batch A: `d` becomes 10, but is not evaluated yet (the `<span>` is deferred)
|
||||||
|
s.click();
|
||||||
|
await tick();
|
||||||
|
|
||||||
|
// batch B
|
||||||
|
u.click();
|
||||||
|
await tick();
|
||||||
|
|
||||||
|
// batch C overrides `d` while A and B are pending. This must not mark `d` as
|
||||||
|
// clean, because the other batches haven't seen its new value (10) yet
|
||||||
|
d.click();
|
||||||
|
await tick();
|
||||||
|
|
||||||
|
// B sees A's change (but not C's), so `d` is 10 in its world
|
||||||
|
resolve_b.click();
|
||||||
|
await tick();
|
||||||
|
assert.equal(logs[0], 'probe 10');
|
||||||
|
|
||||||
|
resolve_a.click();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, `${buttons}<p>1</p><p>0</p><span>10</span><i>10</i>`);
|
||||||
|
|
||||||
|
resolve_c.click();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, `${buttons}<p>1</p><p>1</p><span>99</span><i>99</i>`);
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
<script>
|
||||||
|
let s = $state(0);
|
||||||
|
let u = $state(0);
|
||||||
|
let w = $state(0);
|
||||||
|
let show = $state(true);
|
||||||
|
let d = $derived(s * 10);
|
||||||
|
|
||||||
|
const pending = new Map();
|
||||||
|
|
||||||
|
function delay(name, value) {
|
||||||
|
if (!value) return value;
|
||||||
|
return new Promise((resolve) => pending.set(name, () => resolve(value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function probe(value) {
|
||||||
|
console.log(`probe ${value}`);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button onclick={() => s++}>s</button>
|
||||||
|
<button onclick={() => u++}>u</button>
|
||||||
|
<button
|
||||||
|
onclick={() => {
|
||||||
|
d = 99;
|
||||||
|
w++;
|
||||||
|
}}>d</button
|
||||||
|
>
|
||||||
|
<button onclick={() => pending.get('a')?.()}>resolve a</button>
|
||||||
|
<button onclick={() => pending.get('b')?.()}>resolve b</button>
|
||||||
|
<button onclick={() => pending.get('c')?.()}>resolve c</button>
|
||||||
|
|
||||||
|
<p>{await delay('a', s)}</p>
|
||||||
|
<p>{await delay('c', w)}</p>
|
||||||
|
<!-- inside a branch, so that B's traversal doesn't reach (and stash) the effect reading `d` -->
|
||||||
|
{#if show}
|
||||||
|
<span>{d}</span>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if await delay('b', u)}
|
||||||
|
<i>{await probe(d)}</i>
|
||||||
|
{/if}
|
||||||
Loading…
Reference in new issue