fix: improve nested effect heuristics (#10171)

pull/10172/head
Dominic Gannaway 2 years ago committed by GitHub
parent 0eca0ace94
commit 05bd922f7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: improve nested effect heuristics

@ -624,6 +624,13 @@ export function schedule_effect(signal, sync) {
} }
if ((flags & EFFECT) !== 0) { if ((flags & EFFECT) !== 0) {
current_queued_effects.push(signal); current_queued_effects.push(signal);
// Prevent any nested user effects from potentially triggering
// before this effect is scheduled. We know they will be destroyed
// so we can make them inert to avoid having to find them in the
// queue and remove them.
if ((flags & MANAGED) === 0) {
mark_subtree_children_inert(signal, true);
}
} else { } else {
current_queued_pre_and_render_effects.push(signal); current_queued_pre_and_render_effects.push(signal);
} }
@ -1017,6 +1024,23 @@ export function mutate_store(store, expression, new_value) {
/** /**
* @param {import('./types.js').ComputationSignal} signal * @param {import('./types.js').ComputationSignal} signal
* @param {boolean} inert * @param {boolean} inert
* @param {Set<import('./types.js').Block>} [visited_blocks]
* @returns {void}
*/
function mark_subtree_children_inert(signal, inert, visited_blocks) {
const references = signal.r;
if (references !== null) {
let i;
for (i = 0; i < references.length; i++) {
mark_subtree_inert(references[i], inert, visited_blocks);
}
}
}
/**
* @param {import('./types.js').ComputationSignal} signal
* @param {boolean} inert
* @param {Set<import('./types.js').Block>} [visited_blocks]
* @returns {void} * @returns {void}
*/ */
export function mark_subtree_inert(signal, inert, visited_blocks = new Set()) { export function mark_subtree_inert(signal, inert, visited_blocks = new Set()) {
@ -1055,13 +1079,7 @@ export function mark_subtree_inert(signal, inert, visited_blocks = new Set()) {
} }
} }
} }
const references = signal.r; mark_subtree_children_inert(signal, inert, visited_blocks);
if (references !== null) {
let i;
for (i = 0; i < references.length; i++) {
mark_subtree_inert(references[i], inert, visited_blocks);
}
}
} }
/** /**

@ -0,0 +1,28 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
import { log } from './log.js';
export default test({
before_test() {
log.length = 0;
},
async test({ assert, target }) {
const [b1] = target.querySelectorAll('button');
flushSync(() => {
b1?.click();
});
await Promise.resolve();
assert.deepEqual(log, [
'top level',
'inner',
0,
'destroy inner',
undefined,
'destroy outer',
undefined
]);
}
});

@ -0,0 +1,2 @@
/** @type {any[]} */
export const log = [];

@ -0,0 +1,21 @@
<script>
import { log } from './log.js';
let c = $state({ a: 0 });
$effect(() => {
log.push('top level')
$effect(() => {
if (c) {
$effect(() => {
log.push('inner',c.a);
return () => log.push('destroy inner', c?.a);
});
}
return () => log.push('destroy outer', c?.a);
})
});
</script>
<button onclick={() => {
c.a = 1; c = null
}}>toggle</button>
Loading…
Cancel
Save