async-another-try
Simon Holthausen 3 days ago
parent 408d51b362
commit 9fd77d22a5
No known key found for this signature in database

@ -1050,6 +1050,10 @@ export class Batch {
wv_values.set(source, current.wv);
}
for (const [effect, wv] of this.stale_effects) {
wv_values.set(effect, wv);
}
for (let batch = first_batch; batch !== null; batch = batch.next) {
if (batch === this) continue;
@ -1567,8 +1571,9 @@ export function fork(fn) {
}
}
// All the block/async effects the fork executed are now guaranteed to be up to date
for (const effect of batch.stale_effects.keys()) {
effect.wv = effect.wv > write_version ? effect.wv : write_version;
effect.wv = write_version;
}
batch.stale_effects.clear();

@ -189,8 +189,10 @@ export function is_dirty(reaction) {
if (
(flags & CONNECTED) !== 0 &&
// During time traveling we don't want to reset the status so that
// traversal of the graph in the other batches still happens
batch_values === null
// traversal of the graph in the other batches still happens. Effects
// can be reset because block/async effects execute right away and others
// are deferred and re-dirtied as needed.
(batch_values === null || (flags & DERIVED) === 0)
) {
set_signal_status(reaction, CLEAN);
}

@ -0,0 +1,41 @@
import { tick } from 'svelte';
import { test } from '../../test';
const buttons = `
<button>fork</button>
<button>resolve</button>
<button>commit</button>
`;
export default test({
async test({ assert, target, logs }) {
await tick();
const [fork_button, resolve, commit] = target.querySelectorAll('button');
assert.deepEqual(logs, [[0, true]]);
assert.htmlEqual(target.innerHTML, `${buttons}<p>0</p>`);
fork_button.click();
await tick();
assert.deepEqual(logs, [
[0, true],
[2, true]
]);
assert.htmlEqual(target.innerHTML, `${buttons}<p>0</p>`);
// `delayed` changes, but `nonnegative` stays true. The async expression has
// already consumed the fork's `doubled`, so it should not run again.
resolve.click();
await tick();
assert.deepEqual(logs, [
[0, true],
[2, true]
]);
assert.htmlEqual(target.innerHTML, `${buttons}<p>0</p>`);
commit.click();
await tick();
assert.htmlEqual(target.innerHTML, `${buttons}<p>2</p>`);
}
});

@ -0,0 +1,27 @@
<script>
import { fork } from 'svelte';
const resolvers = [];
let f;
let count = $state(0);
let doubled = $derived(count * 2);
let delayed = $derived(await delay(count));
let nonnegative = $derived(delayed >= 0);
function delay(value) {
if (value === 0) return value;
return new Promise((resolve) => resolvers.push(() => resolve(value)));
}
function load(value, nonnegative) {
console.log([value, nonnegative]);
return value;
}
</script>
<button onclick={() => (f = fork(() => count++))}>fork</button>
<button onclick={() => resolvers.shift()?.()}>resolve</button>
<button onclick={() => f?.commit()}>commit</button>
<p>{await load(doubled, nonnegative)}</p>
Loading…
Cancel
Save