@@ -349,7 +349,21 @@ function execute_signal_fn(signal) {
349
349
350
350
if ( current_dependencies !== null ) {
351
351
let i ;
352
- remove_consumer ( signal , current_dependencies_index , false ) ;
352
+ if ( dependencies !== null ) {
353
+ const dep_length = dependencies . length ;
354
+ // If we have more than 16 elements in the array then use a Set for faster performance
355
+ // TODO: evaluate if we should always just use a Set or not here?
356
+ const current_dependencies_set = dep_length > 16 ? new Set ( current_dependencies ) : null ;
357
+ for ( i = current_dependencies_index ; i < dep_length ; i ++ ) {
358
+ const dependency = dependencies [ i ] ;
359
+ if (
360
+ ( current_dependencies_set !== null && ! current_dependencies_set . has ( dependency ) ) ||
361
+ ! current_dependencies . includes ( dependency )
362
+ ) {
363
+ remove_consumer ( signal , dependency , false ) ;
364
+ }
365
+ }
366
+ }
353
367
354
368
if ( dependencies !== null && current_dependencies_index > 0 ) {
355
369
dependencies . length = current_dependencies_index + current_dependencies . length ;
@@ -365,16 +379,17 @@ function execute_signal_fn(signal) {
365
379
if ( ! current_skip_consumer ) {
366
380
for ( i = current_dependencies_index ; i < dependencies . length ; i ++ ) {
367
381
const dependency = dependencies [ i ] ;
382
+ const consumers = dependency . c ;
368
383
369
- if ( dependency . c === null ) {
384
+ if ( consumers === null ) {
370
385
dependency . c = [ signal ] ;
371
- } else {
372
- dependency . c . push ( signal ) ;
386
+ } else if ( consumers [ consumers . length - 1 ] !== signal ) {
387
+ consumers . push ( signal ) ;
373
388
}
374
389
}
375
390
}
376
391
} else if ( dependencies !== null && current_dependencies_index < dependencies . length ) {
377
- remove_consumer ( signal , current_dependencies_index , false ) ;
392
+ remove_consumers ( signal , current_dependencies_index , false ) ;
378
393
dependencies . length = current_dependencies_index ;
379
394
}
380
395
return res ;
@@ -390,43 +405,54 @@ function execute_signal_fn(signal) {
390
405
}
391
406
}
392
407
408
+ /**
409
+ * @template V
410
+ * @param {import('./types.js').ComputationSignal<V> } signal
411
+ * @param {import('./types.js').Signal<V> } dependency
412
+ * @param {boolean } remove_unowned
413
+ * @returns {void }
414
+ */
415
+ function remove_consumer ( signal , dependency , remove_unowned ) {
416
+ const consumers = dependency . c ;
417
+ let consumers_length = 0 ;
418
+ if ( consumers !== null ) {
419
+ consumers_length = consumers . length - 1 ;
420
+ const index = consumers . indexOf ( signal ) ;
421
+ if ( index !== - 1 ) {
422
+ if ( consumers_length === 0 ) {
423
+ dependency . c = null ;
424
+ } else {
425
+ // Swap with last element and then remove.
426
+ consumers [ index ] = consumers [ consumers_length ] ;
427
+ consumers . pop ( ) ;
428
+ }
429
+ }
430
+ }
431
+ if ( remove_unowned && consumers_length === 0 && ( dependency . f & UNOWNED ) !== 0 ) {
432
+ // If the signal is unowned then we need to make sure to change it to dirty.
433
+ set_signal_status ( dependency , DIRTY ) ;
434
+ remove_consumers (
435
+ /** @type {import('./types.js').ComputationSignal<V> } **/ ( dependency ) ,
436
+ 0 ,
437
+ true
438
+ ) ;
439
+ }
440
+ }
441
+
393
442
/**
394
443
* @template V
395
444
* @param {import('./types.js').ComputationSignal<V> } signal
396
445
* @param {number } start_index
397
446
* @param {boolean } remove_unowned
398
447
* @returns {void }
399
448
*/
400
- function remove_consumer ( signal , start_index , remove_unowned ) {
449
+ function remove_consumers ( signal , start_index , remove_unowned ) {
401
450
const dependencies = signal . d ;
402
451
if ( dependencies !== null ) {
403
452
let i ;
404
453
for ( i = start_index ; i < dependencies . length ; i ++ ) {
405
454
const dependency = dependencies [ i ] ;
406
- const consumers = dependency . c ;
407
- let consumers_length = 0 ;
408
- if ( consumers !== null ) {
409
- consumers_length = consumers . length - 1 ;
410
- const index = consumers . indexOf ( signal ) ;
411
- if ( index !== - 1 ) {
412
- if ( consumers_length === 0 ) {
413
- dependency . c = null ;
414
- } else {
415
- // Swap with last element and then remove.
416
- consumers [ index ] = consumers [ consumers_length ] ;
417
- consumers . pop ( ) ;
418
- }
419
- }
420
- }
421
- if ( remove_unowned && consumers_length === 0 && ( dependency . f & UNOWNED ) !== 0 ) {
422
- // If the signal is unowned then we need to make sure to change it to dirty.
423
- set_signal_status ( dependency , DIRTY ) ;
424
- remove_consumer (
425
- /** @type {import('./types.js').ComputationSignal<V> } **/ ( dependency ) ,
426
- 0 ,
427
- true
428
- ) ;
429
- }
455
+ remove_consumer ( signal , dependency , remove_unowned ) ;
430
456
}
431
457
}
432
458
}
@@ -446,7 +472,7 @@ function destroy_references(signal) {
446
472
if ( ( reference . f & IS_EFFECT ) !== 0 ) {
447
473
destroy_signal ( reference ) ;
448
474
} else {
449
- remove_consumer ( reference , 0 , true ) ;
475
+ remove_consumers ( reference , 0 , true ) ;
450
476
reference . d = null ;
451
477
}
452
478
}
@@ -841,10 +867,16 @@ export function get(signal) {
841
867
! ( unowned && current_effect !== null )
842
868
) {
843
869
current_dependencies_index ++ ;
844
- } else if ( current_dependencies === null ) {
845
- current_dependencies = [ signal ] ;
846
- } else if ( signal !== current_dependencies [ current_dependencies . length - 1 ] ) {
847
- current_dependencies . push ( signal ) ;
870
+ } else if (
871
+ dependencies === null ||
872
+ current_dependencies_index === 0 ||
873
+ dependencies [ current_dependencies_index - 1 ] !== signal
874
+ ) {
875
+ if ( current_dependencies === null ) {
876
+ current_dependencies = [ signal ] ;
877
+ } else if ( signal !== current_dependencies [ current_dependencies . length - 1 ] ) {
878
+ current_dependencies . push ( signal ) ;
879
+ }
848
880
}
849
881
if (
850
882
current_untracked_writes !== null &&
@@ -1098,7 +1130,7 @@ export function destroy_signal(signal) {
1098
1130
const destroy = signal . y ;
1099
1131
const flags = signal . f ;
1100
1132
destroy_references ( signal ) ;
1101
- remove_consumer ( signal , 0 , true ) ;
1133
+ remove_consumers ( signal , 0 , true ) ;
1102
1134
signal . i =
1103
1135
signal . r =
1104
1136
signal . y =
0 commit comments