Skip to content

Commit 6f0e43d

Browse files
committed
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
1 parent 2e02868 commit 6f0e43d

File tree

5 files changed

+50
-1
lines changed

5 files changed

+50
-1
lines changed

.changeset/shaggy-donuts-wait.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: avoid false-positive infinite loop error

packages/svelte/src/internal/client/reactivity/batch.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ let last_scheduled_effect = null;
7878
let is_flushing = false;
7979

8080
let is_flushing_sync = false;
81+
82+
/** @type {Map<Effect, number>} */
83+
let effect_execution_count = new Map();
84+
85+
let flush_count = 0;
86+
8187
export class Batch {
8288
/**
8389
* The current values of any sources that are updated in this batch
@@ -526,7 +532,7 @@ function flush_effects() {
526532
is_flushing = true;
527533

528534
try {
529-
var flush_count = 0;
535+
flush_count = 0;
530536
set_is_updating_effect(true);
531537

532538
while (queued_root_effects.length > 0) {
@@ -564,6 +570,7 @@ function flush_effects() {
564570
} finally {
565571
is_flushing = false;
566572
set_is_updating_effect(was_updating_effect);
573+
effect_execution_count.clear();
567574

568575
last_scheduled_effect = null;
569576
}
@@ -626,6 +633,17 @@ function flush_queued_effects(effects) {
626633
current_batch.current.size > n &&
627634
(effect.f & USER_EFFECT) !== 0
628635
) {
636+
var execution_count = (effect_execution_count.get(effect) ?? 0) + 1;
637+
effect_execution_count.set(effect, execution_count);
638+
639+
// If many effects are executed, they cause another flush loop, which could
640+
// lead to false-positives in the infinite loop detection. Therefore decrease
641+
// the counter unless the individual effect has been executed many times, which
642+
// indeed hints at an infinite loop.
643+
if (execution_count < 1000) {
644+
flush_count--;
645+
}
646+
629647
break;
630648
}
631649
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script>
2+
let a = $state(0);
3+
$effect(() => {
4+
a = 1;
5+
});
6+
</script>
7+
8+
{a}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
mode: ['client', 'hydrate'],
5+
6+
compileOptions: {
7+
dev: true
8+
},
9+
10+
html: `1`.repeat(2000)
11+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
import Component from './Component.svelte';
3+
</script>
4+
5+
{#each Array(2000) as _, i}
6+
<Component />
7+
{/each}

0 commit comments

Comments
 (0)