@@ -484,72 +484,92 @@ export function schedule_effect(signal) {
484484
485485/**
486486 *
487- * This function recursively collects effects in topological order from the starting effect passed in.
488- * Effects will be collected when they match the filtered bitwise flag passed in only. The collected
489- * array will be populated with all the effects.
490- *
491- * In an ideal world, we could just execute effects as we encounter them using this approach. However,
492- * this isn't possible due to how effects in Svelte are modelled to be possibly side-effectful. Thus,
493- * executing an effect might invalidate other parts of the tree, which means this this tree walking function
494- * will possibly pick up effects that are dirty too soon.
487+ * This function both runs render effects and collects user effects in topological order
488+ * from the starting effect passed in. Effects will be collected when they match the filtered
489+ * bitwise flag passed in only. The collected effects array will be populated with all the user
490+ * effects to be flushed.
495491 *
496492 * @param {import('./types.js').Effect } effect
497493 * @param {number } filter_flags
498494 * @param {boolean } shallow
499- * @param {import('./types.js').Effect[] } collected_user
495+ * @param {import('./types.js').Effect[] } collected_effects
500496 * @returns {void }
501497 */
502- function recursively_process_effects ( effect , filter_flags , shallow , collected_user ) {
503- var current_child = effect . first ;
504- var user = [ ] ;
505-
506- while ( current_child !== null ) {
507- var child = current_child ;
508- current_child = child . next ;
509- var flags = child . f ;
510- var is_inactive = ( flags & ( DESTROYED | INERT ) ) !== 0 ;
511- if ( is_inactive ) continue ;
498+ function process_effects ( effect , filter_flags , shallow , collected_effects ) {
499+ var current_effect = effect . first ;
500+ var effects = [ ] ;
501+
502+ main_loop: while ( current_effect !== null ) {
503+ var flags = current_effect . f ;
504+ // TODO: we probably don't need to check for destroyed as it shouldn't be encountered?
505+ var is_active = ( flags & ( DESTROYED | INERT ) ) === 0 ;
512506 var is_branch = flags & BRANCH_EFFECT ;
513507 var is_clean = ( flags & CLEAN ) !== 0 ;
508+ var child = current_effect . first ;
514509
515- if ( is_branch ) {
516- // Skip this branch if it's clean
517- if ( is_clean ) continue ;
518- set_signal_status ( child , CLEAN ) ;
519- }
520-
521- if ( ( flags & RENDER_EFFECT ) !== 0 ) {
510+ // Skip this branch if it's clean
511+ if ( is_active && ( ! is_branch || ! is_clean ) ) {
522512 if ( is_branch ) {
523- if ( shallow ) continue ;
524- // TODO we don't need to call recursively_process_effects recursively with a linked list in place
525- recursively_process_effects ( child , filter_flags , false , collected_user ) ;
526- } else {
527- if ( check_dirtiness ( child ) ) {
528- execute_effect ( child ) ;
513+ set_signal_status ( current_effect , CLEAN ) ;
514+ }
515+
516+ if ( ( flags & RENDER_EFFECT ) !== 0 ) {
517+ if ( is_branch ) {
518+ if ( ! shallow && child !== null ) {
519+ current_effect = child ;
520+ continue ;
521+ }
522+ } else {
523+ if ( check_dirtiness ( current_effect ) ) {
524+ execute_effect ( current_effect ) ;
525+ // Child might have been mutated since running the effect
526+ child = current_effect . first ;
527+ }
528+ if ( ! shallow && child !== null ) {
529+ current_effect = child ;
530+ continue ;
531+ }
532+ }
533+ } else if ( ( flags & EFFECT ) !== 0 ) {
534+ if ( is_branch || is_clean ) {
535+ if ( ! shallow && child !== null ) {
536+ current_effect = child ;
537+ continue ;
538+ }
539+ } else {
540+ effects . push ( current_effect ) ;
529541 }
530- // TODO we don't need to call recursively_process_effects recursively with a linked list in place
531- recursively_process_effects ( child , filter_flags , false , collected_user ) ;
532542 }
533- } else if ( ( flags & EFFECT ) !== 0 ) {
534- if ( is_branch || is_clean ) {
535- if ( shallow ) continue ;
536- // TODO we don't need to call recursively_process_effects recursively with a linked list in place
537- recursively_process_effects ( child , filter_flags , false , collected_user ) ;
538- } else {
539- user . push ( child ) ;
543+ }
544+ var sibling = current_effect . next ;
545+
546+ if ( sibling === null ) {
547+ let parent = current_effect . parent ;
548+
549+ while ( parent !== null ) {
550+ if ( effect === parent ) {
551+ break main_loop;
552+ }
553+ var parent_sibling = parent . next ;
554+ if ( parent_sibling !== null ) {
555+ current_effect = parent_sibling ;
556+ continue main_loop;
557+ }
558+ parent = parent . parent ;
540559 }
541560 }
561+
562+ current_effect = sibling ;
542563 }
543564
544- if ( user . length > 0 ) {
565+ if ( effects . length > 0 ) {
545566 if ( ( filter_flags & EFFECT ) !== 0 ) {
546- collected_user . push ( ...user ) ;
567+ collected_effects . push ( ...effects ) ;
547568 }
548569
549570 if ( ! shallow ) {
550- for ( var i = 0 ; i < user . length ; i ++ ) {
551- // TODO we don't need to call recursively_process_effects recursively with a linked list in place
552- recursively_process_effects ( user [ i ] , filter_flags , false , collected_user ) ;
571+ for ( var i = 0 ; i < effects . length ; i ++ ) {
572+ process_effects ( effects [ i ] , filter_flags , false , collected_effects ) ;
553573 }
554574 }
555575 }
@@ -568,7 +588,7 @@ function recursively_process_effects(effect, filter_flags, shallow, collected_us
568588 */
569589function flush_nested_effects ( effect , filter_flags , shallow = false ) {
570590 /** @type {import('#client').Effect[] } */
571- var user_effects = [ ] ;
591+ var collected_effects = [ ] ;
572592
573593 var previously_flushing_effect = is_flushing_effect ;
574594 is_flushing_effect = true ;
@@ -578,8 +598,8 @@ function flush_nested_effects(effect, filter_flags, shallow = false) {
578598 if ( effect . first === null && ( effect . f & BRANCH_EFFECT ) === 0 ) {
579599 flush_queued_effects ( [ effect ] ) ;
580600 } else {
581- recursively_process_effects ( effect , filter_flags , shallow , user_effects ) ;
582- flush_queued_effects ( user_effects ) ;
601+ process_effects ( effect , filter_flags , shallow , collected_effects ) ;
602+ flush_queued_effects ( collected_effects ) ;
583603 }
584604 } finally {
585605 is_flushing_effect = previously_flushing_effect ;
0 commit comments