fix: exclude derived writes from effect abort and rescheduling

1000-reading-derived-effects
paoloricciuti 1 month ago
parent 9412c5861c
commit cfd6446635

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: exclude derived writes from effect abort and rescheduling

@ -31,6 +31,7 @@ import { invoke_error_boundary } from '../error-handling.js';
import { old_values } from './sources.js';
import { unlink_effect } from './effects.js';
import { unset_context } from './async.js';
import { get_derived_writes, reset_derived_writes } from './deriveds.js';
/** @type {Set<Batch>} */
const batches = new Set();
@ -546,6 +547,12 @@ function flush_queued_effects(effects) {
if (is_dirty(effect)) {
var wv = write_version;
// updating a derived for also increase the write version but that doesn't mean
// state was written to in the user effect...so we reset the derived writes
// before running the effect so that we can subtract the amount of derived writes
// from the write version when we detect if state was written to in the user effect
reset_derived_writes();
update_effect(effect);
// Effects with no dependencies or teardown do not get added to the effect tree.
@ -567,7 +574,7 @@ function flush_queued_effects(effects) {
// if state is written in a user effect, abort and re-schedule, lest we run
// effects that should be removed as a result of the state change
if (write_version > wv && (effect.f & USER_EFFECT) !== 0) {
if (write_version - get_derived_writes() > wv && (effect.f & USER_EFFECT) !== 0) {
break;
}
}

@ -323,6 +323,20 @@ export function execute_derived(derived) {
return value;
}
// in process_effects if state is written to in a user effect we reschedule the rest of the
// tree. However if a derived is updated in an effect we also increase the write version
// so we need to keep track of how many deriveds were written to in the effect so
// that we can subtract that from the write version before rescheduling unnnecessarily
let derived_writes = 0;
export function get_derived_writes() {
return derived_writes;
}
export function reset_derived_writes() {
derived_writes = 0;
}
/**
* @param {Derived} derived
* @returns {void}
@ -333,6 +347,7 @@ export function update_derived(derived) {
if (!derived.equals(value)) {
derived.v = value;
derived.wv = increment_write_version();
derived_writes++;
}
// don't mark derived clean if we're reading it inside a

@ -0,0 +1,7 @@
<script>
const der = $derived(false);
$effect(() => {
der
});
</script>

@ -0,0 +1,5 @@
import { test } from '../../test';
export default test({
async test() {}
});

@ -0,0 +1,8 @@
<script>
import Component from './Component.svelte'
const arr = Array.from({length: 10001});
</script>
{#each arr}
<Component />
{/each}
Loading…
Cancel
Save