@ -25,10 +25,7 @@ import {
MAYBE _DIRTY ,
BLOCK _EFFECT ,
ROOT _EFFECT ,
ASYNC ,
WAS _MARKED ,
CONNECTED ,
REACTION _IS _UPDATING
ASYNC
} from '#client/constants' ;
import * as e from '../errors.js' ;
import { legacy _mode _flag , tracing _mode _flag } from '../../flags/index.js' ;
@ -171,6 +168,17 @@ export function set(source, value, should_proxy = false) {
return internal _set ( source , new _value , legacy _updates ) ;
}
/ * *
* A set of signals we have already seen while traversing in mark _reactions .
* Not always set to balance the common case of sources only having a couple
* of ( transitive ) dependencies ( where always creating a Set would be bad for perf )
* with the edge case of extremely deep or wide dependency arrays with cycles .
* @ type { Set < any > | null }
* /
var seen = null ;
/** Number of transitive dependencies, see {@link seen} for more info */
var count _deps = 0 ;
/ * *
* @ template V
* @ param { Source < V > } source
@ -240,7 +248,10 @@ export function internal_set(source, value, updated_during_traversal = null) {
// For debugging, in case you want to know which reactions are being scheduled:
// log_reactions(source);
seen = null ;
count _deps = 0 ;
mark _reactions ( source , DIRTY , updated _during _traversal ) ;
seen = null ;
// It's possible that the current reaction might not have up-to-date dependencies
// whilst it's actively running. So in the case of ensuring it registers the reaction
@ -347,6 +358,18 @@ function mark_reactions(signal, status, updated_during_traversal) {
var runes = is _runes ( ) ;
var length = reactions . length ;
count _deps += length ;
// Activate the `seen` Set if we think from the unusually high number of deps that
// there might be cycles in the graph, to avoid repeated lookups for reactions
// Example: https://github.com/sveltejs/svelte/issues/16658 has a graph with one source
// reaching ~10000 distinct deriveds/effects each, resulting in 65 million walks through repeated visits.
if ( count _deps > 100000 && seen === null ) seen = new Set ( ) ;
if ( seen !== null ) {
if ( seen . has ( signal ) ) return ;
seen . add ( signal ) ;
}
for ( var i = 0 ; i < length ; i ++ ) {
var reaction = reactions [ i ] ;
var flags = reaction . f ;
@ -370,18 +393,7 @@ function mark_reactions(signal, status, updated_during_traversal) {
var derived = /** @type {Derived} */ ( reaction ) ;
batch _values ? . delete ( derived ) ;
if ( ( flags & WAS _MARKED ) === 0 ) {
// Only connected deriveds being executed outside the update cycle can be reliably unmarked right away
if (
flags & CONNECTED &&
( active _effect === null || ( active _effect . f & REACTION _IS _UPDATING ) === 0 )
) {
reaction . f |= WAS _MARKED ;
}
mark _reactions ( derived , MAYBE _DIRTY , updated _during _traversal ) ;
}
mark _reactions ( derived , MAYBE _DIRTY , updated _during _traversal ) ;
} else if ( not _dirty ) {
var effect = /** @type {Effect} */ ( reaction ) ;