@@ -15,9 +15,11 @@ import { untrack } from '../../runtime.js';
15
15
import {
16
16
block ,
17
17
branch ,
18
+ destroy_effect ,
18
19
effect ,
20
+ run_out_transitions ,
21
+ pause_children ,
19
22
pause_effect ,
20
- pause_effects ,
21
23
resume_effect
22
24
} from '../../reactivity/effects.js' ;
23
25
import { source , mutable_source , set } from '../../reactivity/sources.js' ;
@@ -39,6 +41,39 @@ export function set_current_each_item(item) {
39
41
current_each_item = item ;
40
42
}
41
43
44
+ /**
45
+ * Pause multiple effects simultaneously, and coordinate their
46
+ * subsequent destruction. Used in each blocks
47
+ * @param {import('#client').Effect[] } effects
48
+ * @param {null | Node } controlled_anchor
49
+ * @param {() => void } [callback]
50
+ */
51
+ function pause_effects ( effects , controlled_anchor , callback ) {
52
+ /** @type {import('#client').TransitionManager[] } */
53
+ var transitions = [ ] ;
54
+ var length = effects . length ;
55
+
56
+ for ( var i = 0 ; i < length ; i ++ ) {
57
+ pause_children ( effects [ i ] , transitions , true ) ;
58
+ }
59
+
60
+ // If we have a controlled anchor, it means that the each block is inside a single
61
+ // DOM element, so we can apply a fast-path for clearing the contents of the element.
62
+ if ( effects . length > 0 && transitions . length === 0 && controlled_anchor !== null ) {
63
+ var parent_node = /** @type {Element } */ ( controlled_anchor . parentNode ) ;
64
+ parent_node . textContent = '' ;
65
+ parent_node . append ( controlled_anchor ) ;
66
+ }
67
+
68
+ run_out_transitions ( transitions , ( ) => {
69
+ for ( var i = 0 ; i < length ; i ++ ) {
70
+ destroy_effect ( effects [ i ] ) ;
71
+ }
72
+
73
+ if ( callback !== undefined ) callback ( ) ;
74
+ } ) ;
75
+ }
76
+
42
77
/**
43
78
* @template V
44
79
* @param {Element | Comment } anchor The next sibling node, or the parent node if this is a 'controlled' block
@@ -145,7 +180,6 @@ function each(anchor, flags, get_collection, get_key, render_fn, fallback_fn, re
145
180
}
146
181
147
182
if ( ! hydrating ) {
148
- // TODO add 'empty controlled block' optimisation here
149
183
reconcile_fn ( array , state , anchor , render_fn , flags , keys ) ;
150
184
}
151
185
@@ -244,7 +278,9 @@ function reconcile_indexed_array(array, state, anchor, render_fn, flags) {
244
278
effects . push ( a_items [ i ] . e ) ;
245
279
}
246
280
247
- pause_effects ( effects , ( ) => {
281
+ var controlled_anchor = ( flags & EACH_IS_CONTROLLED ) !== 0 && b === 0 ? anchor : null ;
282
+
283
+ pause_effects ( effects , controlled_anchor , ( ) => {
248
284
state . items . length = b ;
249
285
} ) ;
250
286
}
@@ -274,6 +310,7 @@ function reconcile_tracked_array(array, state, anchor, render_fn, flags, keys) {
274
310
275
311
var is_animated = ( flags & EACH_IS_ANIMATED ) !== 0 ;
276
312
var should_update = ( flags & ( EACH_ITEM_REACTIVE | EACH_INDEX_REACTIVE ) ) !== 0 ;
313
+ var is_controlled = ( flags & EACH_IS_CONTROLLED ) !== 0 ;
277
314
var start = 0 ;
278
315
var item ;
279
316
@@ -381,6 +418,11 @@ function reconcile_tracked_array(array, state, anchor, render_fn, flags, keys) {
381
418
// I fully understand this part)
382
419
if ( moved ) {
383
420
mark_lis ( sources ) ;
421
+ } else if ( is_controlled && to_destroy . length === a_items . length ) {
422
+ // We can optimize the case in which all items are replaced —
423
+ // destroy everything first, then append new items
424
+ pause_effects ( to_destroy , anchor ) ;
425
+ to_destroy = [ ] ;
384
426
}
385
427
386
428
// working from the back, insert new or moved items
@@ -421,9 +463,9 @@ function reconcile_tracked_array(array, state, anchor, render_fn, flags, keys) {
421
463
} ) ;
422
464
}
423
465
424
- // TODO: would be good to avoid this closure in the case where we have no
425
- // transitions at all. It would make it far more JIT friendly in the hot cases.
426
- pause_effects ( to_destroy , ( ) => {
466
+ var controlled_anchor = is_controlled && b_items . length === 0 ? anchor : null ;
467
+
468
+ pause_effects ( to_destroy , controlled_anchor , ( ) => {
427
469
state . items = b_items ;
428
470
} ) ;
429
471
}
0 commit comments