@@ -54,6 +54,8 @@ export let current_effect = null;
54
54
/** @type {null | import('./types.js').Signal[] } */
55
55
let current_dependencies = null ;
56
56
let current_dependencies_index = 0 ;
57
+ /** @type {null | import('./types.js').Signal[] } */
58
+ let current_untracked_writes = null ;
57
59
// Handling capturing of signals from object property getters
58
60
let current_should_capture_signal = false ;
59
61
/** If `true`, `get`ting the signal should not register it as a dependency */
@@ -282,6 +284,7 @@ function execute_signal_fn(signal) {
282
284
const init = signal . i ;
283
285
const previous_dependencies = current_dependencies ;
284
286
const previous_dependencies_index = current_dependencies_index ;
287
+ const previous_untracked_writes = current_untracked_writes ;
285
288
const previous_consumer = current_consumer ;
286
289
const previous_block = current_block ;
287
290
const previous_component_context = current_component_context ;
@@ -290,6 +293,7 @@ function execute_signal_fn(signal) {
290
293
const previous_untracking = current_untracking ;
291
294
current_dependencies = /** @type {null | import('./types.js').Signal[] } */ ( null ) ;
292
295
current_dependencies_index = 0 ;
296
+ current_untracked_writes = null ;
293
297
current_consumer = signal ;
294
298
current_block = signal . b ;
295
299
current_component_context = signal . x ;
@@ -347,6 +351,7 @@ function execute_signal_fn(signal) {
347
351
} finally {
348
352
current_dependencies = previous_dependencies ;
349
353
current_dependencies_index = previous_dependencies_index ;
354
+ current_untracked_writes = previous_untracked_writes ;
350
355
current_consumer = previous_consumer ;
351
356
current_block = previous_block ;
352
357
current_component_context = previous_component_context ;
@@ -469,23 +474,27 @@ export function execute_effect(signal) {
469
474
}
470
475
}
471
476
477
+ function infinite_loop_guard ( ) {
478
+ if ( flush_count > 100 ) {
479
+ throw new Error (
480
+ 'ERR_SVELTE_TOO_MANY_UPDATES' +
481
+ ( DEV
482
+ ? ': Maximum update depth exceeded. This can happen when a reactive block or effect ' +
483
+ 'repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops.'
484
+ : '' )
485
+ ) ;
486
+ }
487
+ flush_count ++ ;
488
+ }
489
+
472
490
/**
473
491
* @param {Array<import('./types.js').EffectSignal> } effects
474
492
* @returns {void }
475
493
*/
476
494
function flush_queued_effects ( effects ) {
477
495
const length = effects . length ;
478
496
if ( length > 0 ) {
479
- if ( flush_count > 100 ) {
480
- throw new Error (
481
- 'ERR_SVELTE_TOO_MANY_UPDATES' +
482
- ( DEV
483
- ? ': Maximum update depth exceeded. This can happen when a reactive block or effect ' +
484
- 'repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops.'
485
- : '' )
486
- ) ;
487
- }
488
- flush_count ++ ;
497
+ infinite_loop_guard ( ) ;
489
498
let i ;
490
499
for ( i = 0 ; i < length ; i ++ ) {
491
500
const signal = effects [ i ] ;
@@ -606,13 +615,13 @@ export function flushSync(fn) {
606
615
const previous_queued_pre_and_render_effects = current_queued_pre_and_render_effects ;
607
616
const previous_queued_effects = current_queued_effects ;
608
617
try {
618
+ infinite_loop_guard ( ) ;
609
619
/** @type {import('./types.js').EffectSignal[] } */
610
620
const pre_and_render_effects = [ ] ;
611
621
612
622
/** @type {import('./types.js').EffectSignal[] } */
613
623
const effects = [ ] ;
614
624
current_scheduler_mode = FLUSH_SYNC ;
615
- flush_count = 0 ;
616
625
current_queued_pre_and_render_effects = pre_and_render_effects ;
617
626
current_queued_effects = effects ;
618
627
flush_queued_effects ( previous_queued_pre_and_render_effects ) ;
@@ -626,6 +635,7 @@ export function flushSync(fn) {
626
635
if ( is_task_queued ) {
627
636
process_task ( ) ;
628
637
}
638
+ flush_count = 0 ;
629
639
} finally {
630
640
current_scheduler_mode = previous_scheduler_mode ;
631
641
current_queued_pre_and_render_effects = previous_queued_pre_and_render_effects ;
@@ -814,6 +824,15 @@ export function get(signal) {
814
824
} else if ( signal !== current_dependencies [ current_dependencies . length - 1 ] ) {
815
825
current_dependencies . push ( signal ) ;
816
826
}
827
+ if (
828
+ current_untracked_writes !== null &&
829
+ current_effect !== null &&
830
+ ( current_effect . f & CLEAN ) !== 0 &&
831
+ current_untracked_writes . includes ( signal )
832
+ ) {
833
+ set_signal_status ( current_effect , DIRTY ) ;
834
+ schedule_effect ( current_effect , false ) ;
835
+ }
817
836
}
818
837
819
838
if ( ( flags & DERIVED ) !== 0 && is_signal_dirty ( signal ) ) {
@@ -1024,12 +1043,18 @@ export function set_signal_value(signal, value) {
1024
1043
is_runes ( component_context ) &&
1025
1044
current_effect !== null &&
1026
1045
current_effect . c === null &&
1027
- ( current_effect . f & CLEAN ) !== 0 &&
1028
- current_dependencies !== null &&
1029
- current_dependencies . includes ( signal )
1046
+ ( current_effect . f & CLEAN ) !== 0
1030
1047
) {
1031
- set_signal_status ( current_effect , DIRTY ) ;
1032
- schedule_effect ( current_effect , false ) ;
1048
+ if ( current_dependencies !== null && current_dependencies . includes ( signal ) ) {
1049
+ set_signal_status ( current_effect , DIRTY ) ;
1050
+ schedule_effect ( current_effect , false ) ;
1051
+ } else {
1052
+ if ( current_untracked_writes === null ) {
1053
+ current_untracked_writes = [ signal ] ;
1054
+ } else {
1055
+ current_untracked_writes . push ( signal ) ;
1056
+ }
1057
+ }
1033
1058
}
1034
1059
mark_signal_consumers ( signal , DIRTY , true ) ;
1035
1060
// If we have afterUpdates locally on the component, but we're within a render effect
0 commit comments