fix: avoid false-positive infinite loop error

Checks each effect's execution count and only advances the overall flush count if an inidivual effect was executed many times, hinting at a loop

The count overall is kept in place because theoretically there could be other infinite loops happening with no user effect in the mix.

Fixes part of #16548
pull/16611/head
Simon Holthausen 3 weeks ago
parent 2e02868ef1
commit 6f0e43de1a

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: avoid false-positive infinite loop error

@ -78,6 +78,12 @@ let last_scheduled_effect = null;
let is_flushing = false;
let is_flushing_sync = false;
/** @type {Map<Effect, number>} */
let effect_execution_count = new Map();
let flush_count = 0;
export class Batch {
/**
* The current values of any sources that are updated in this batch
@ -526,7 +532,7 @@ function flush_effects() {
is_flushing = true;
try {
var flush_count = 0;
flush_count = 0;
set_is_updating_effect(true);
while (queued_root_effects.length > 0) {
@ -564,6 +570,7 @@ function flush_effects() {
} finally {
is_flushing = false;
set_is_updating_effect(was_updating_effect);
effect_execution_count.clear();
last_scheduled_effect = null;
}
@ -626,6 +633,17 @@ function flush_queued_effects(effects) {
current_batch.current.size > n &&
(effect.f & USER_EFFECT) !== 0
) {
var execution_count = (effect_execution_count.get(effect) ?? 0) + 1;
effect_execution_count.set(effect, execution_count);
// If many effects are executed, they cause another flush loop, which could
// lead to false-positives in the infinite loop detection. Therefore decrease
// the counter unless the individual effect has been executed many times, which
// indeed hints at an infinite loop.
if (execution_count < 1000) {
flush_count--;
}
break;
}
}

@ -0,0 +1,8 @@
<script>
let a = $state(0);
$effect(() => {
a = 1;
});
</script>
{a}

@ -0,0 +1,11 @@
import { test } from '../../test';
export default test({
mode: ['client', 'hydrate'],
compileOptions: {
dev: true
},
html: `1`.repeat(2000)
});

@ -0,0 +1,7 @@
<script>
import Component from './Component.svelte';
</script>
{#each Array(2000) as _, i}
<Component />
{/each}
Loading…
Cancel
Save