fix: ensure resume effects are scheduled in topological order (#15012)

* fix: ensure resume effects are scheduled in topological order

* fix: ensure resume effects are scheduled in topological order
pull/15015/head
Dominic Gannaway 2 days ago committed by GitHub
parent 360ee70dcb
commit 5419610833
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: ensure resume effects are scheduled in topological order

@ -602,17 +602,21 @@ export function resume_effect(effect) {
*/
function resume_children(effect, local) {
if ((effect.f & INERT) === 0) return;
effect.f ^= INERT;
// Ensure the effect is marked as clean again so that any dirty child
// effects can schedule themselves for execution
if ((effect.f & CLEAN) === 0) {
effect.f ^= CLEAN;
}
// If a dependency of this effect changed while it was paused,
// apply the change now
// schedule the effect to update
if (check_dirtiness(effect)) {
update_effect(effect);
set_signal_status(effect, DIRTY);
schedule_effect(effect);
}
// Ensure we toggle the flag after possibly updating the effect so that
// each block logic can correctly operate on inert items
effect.f ^= INERT;
var child = effect.first;
while (child !== null) {

@ -0,0 +1,35 @@
import { flushSync } from '../../../../src/index-client.js';
import { test } from '../../test';
export default test({
async test({ assert, raf, target, logs }) {
assert.htmlEqual(
target.innerHTML,
'<button>Toggle</button><div><div>1</div><div>2</div><div>3</div></div>'
);
const btn1 = target.querySelector('button');
btn1?.click();
flushSync();
raf.tick(250);
assert.htmlEqual(
target.innerHTML,
'<button>Toggle</button><div style="opacity: 0.5;"><div>1</div><div>2</div><div>3</div></div>'
);
logs.length = 0;
await Promise.resolve();
flushSync();
raf.tick(500);
assert.htmlEqual(
target.innerHTML,
'<button>Toggle</button><div style=""><div>3</div><div>4</div></div>'
);
assert.deepEqual(logs, ['$effect.pre', '$effect.pre', '$effect', '$effect']);
}
});

@ -0,0 +1,39 @@
<script>
function fade(_) {
return {
duration: 500,
css: t => `opacity: ${t}`,
}
}
let toggle = $state(true);
let items = $state([ 1, 2, 3 ]);
const handle_toggle = async () => {
toggle = false;
await Promise.resolve();
items = [3, 4];
toggle = true;
};
</script>
<button onclick={handle_toggle}>Toggle</button>
{#if toggle}
<div transition:fade>
{#each items as item (item)}
{(() => {
$effect(() => {
items;
console.log('$effect');
});
$effect.pre(() => {
items;
console.log('$effect.pre');
});
})()}
<div>{item}</div>
{/each}
</div>
{/if}
Loading…
Cancel
Save