@@ -484,72 +484,92 @@ export function schedule_effect(signal) {
484
484
485
485
/**
486
486
*
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.
495
491
*
496
492
* @param {import('./types.js').Effect } effect
497
493
* @param {number } filter_flags
498
494
* @param {boolean } shallow
499
- * @param {import('./types.js').Effect[] } collected_user
495
+ * @param {import('./types.js').Effect[] } collected_effects
500
496
* @returns {void }
501
497
*/
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 ;
512
506
var is_branch = flags & BRANCH_EFFECT ;
513
507
var is_clean = ( flags & CLEAN ) !== 0 ;
508
+ var child = current_effect . first ;
514
509
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 ) ) {
522
512
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 ) ;
529
541
}
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 ) ;
532
542
}
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 ;
540
559
}
541
560
}
561
+
562
+ current_effect = sibling ;
542
563
}
543
564
544
- if ( user . length > 0 ) {
565
+ if ( effects . length > 0 ) {
545
566
if ( ( filter_flags & EFFECT ) !== 0 ) {
546
- collected_user . push ( ...user ) ;
567
+ collected_effects . push ( ...effects ) ;
547
568
}
548
569
549
570
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 ) ;
553
573
}
554
574
}
555
575
}
@@ -568,7 +588,7 @@ function recursively_process_effects(effect, filter_flags, shallow, collected_us
568
588
*/
569
589
function flush_nested_effects ( effect , filter_flags , shallow = false ) {
570
590
/** @type {import('#client').Effect[] } */
571
- var user_effects = [ ] ;
591
+ var collected_effects = [ ] ;
572
592
573
593
var previously_flushing_effect = is_flushing_effect ;
574
594
is_flushing_effect = true ;
@@ -578,8 +598,8 @@ function flush_nested_effects(effect, filter_flags, shallow = false) {
578
598
if ( effect . first === null && ( effect . f & BRANCH_EFFECT ) === 0 ) {
579
599
flush_queued_effects ( [ effect ] ) ;
580
600
} 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 ) ;
583
603
}
584
604
} finally {
585
605
is_flushing_effect = previously_flushing_effect ;
0 commit comments