restore capturing deriveds that match the real value but not the batch's view

Otherwise the batch keeps seeing another batch's previous value for the derived.
async-another-try-pt-1-prune
Rich Harris 2 days ago
parent 737de2e4f3
commit fa16f59447
No known key found for this signature in database

@ -433,6 +433,8 @@ export function update_derived(derived) {
set_signal_status(derived, CLEAN);
return;
}
} else if (batch_values?.has(derived) && !derived.equals(batch_values?.get(derived))) {
current_batch?.capture(derived, derived.v);
}
// don't mark derived clean if we're reading it inside a

@ -0,0 +1,33 @@
import { tick } from 'svelte';
import { test } from '../../test';
const buttons =
'<button>x</button><button>s</button><button>resolve a</button><button>resolve b</button>';
export default test({
mode: ['client'],
async test({ assert, target }) {
await tick();
const [x, s, resolve_a, resolve_b] = target.querySelectorAll('button');
assert.htmlEqual(target.innerHTML, `${buttons}<p>0:5</p><p>5</p>`);
// batch A: `t` becomes truthy (pending)
x.click();
await tick();
// batch B: `d` becomes 0 (pending)
s.click();
await tick();
assert.htmlEqual(target.innerHTML, `${buttons}<p>0:5</p><p>5</p>`);
// In A's world, `d` is recomputed to 0. That's the real value, but not the value
// A sees for it (the one from before B's change), so A has to record it
resolve_a.click();
await tick();
assert.htmlEqual(target.innerHTML, `${buttons}<p>1:0</p><p>5</p>`);
resolve_b.click();
await tick();
assert.htmlEqual(target.innerHTML, `${buttons}<p>1:0</p><p>0</p>`);
}
});

@ -0,0 +1,25 @@
<script>
let x = $state(0);
let s = $state(5);
const pending = new Map();
function delay(name, value, initial) {
if (value === initial) return value;
return new Promise((resolve) => pending.set(name, () => resolve(value)));
}
const t = $derived(await delay('a', x, 0));
const d = $derived(t ? 0 : s);
</script>
<button onclick={() => x++}>x</button>
<button onclick={() => (s = 0)}>s</button>
<button onclick={() => pending.get('a')?.()}>resolve a</button>
<button onclick={() => pending.get('b')?.()}>resolve b</button>
{#if d >= 0}
<p>{t}:{d}</p>
{/if}
<p>{await delay('b', s, 5)}</p>
Loading…
Cancel
Save