@ -1,4 +1,4 @@
/** @import { Derived, Effect, Source, Value } from '#client' */
/** @import { Derived, Effect, Reaction, Source, Value } from '#client' */
import {
BLOCK _EFFECT ,
BRANCH _EFFECT ,
@ -342,31 +342,46 @@ export class Batch {
continue ;
}
/** @type {Source[]} */
const sources = [ ] ;
for ( const [ source , value ] of this . current ) {
if ( batch . current . has ( source ) ) {
if ( is _earlier ) {
if ( is _earlier && value !== batch . current . get ( source ) ) {
// bring the value up to date
batch . current . set ( source , value ) ;
} else {
// later batch has more recent value,
// same value or later batch has more recent value,
// no need to re-run these effects
continue ;
}
}
mark_effects ( source ) ;
sources. push ( source ) ;
}
if ( queued_root _effects . length > 0 ) {
current _batch = batch ;
batch . apply ( ) ;
if ( sources. length === 0 ) {
continue ;
}
for ( const root of queued _root _effects ) {
batch . # traverse _effect _tree ( root ) ;
// Re-run async/block effects that depend on distinct values changed in both batches
const others = [ ... batch . current . keys ( ) ] . filter ( ( s ) => ! this . current . has ( s ) ) ;
if ( others . length > 0 ) {
for ( const source of sources ) {
mark _effects ( source , others ) ;
}
queued _root _effects = [ ] ;
batch . deactivate ( ) ;
if ( queued _root _effects . length > 0 ) {
current _batch = batch ;
batch . apply ( ) ;
for ( const root of queued _root _effects ) {
batch . # traverse _effect _tree ( root ) ;
}
queued _root _effects = [ ] ;
batch . deactivate ( ) ;
}
}
}
@ -621,17 +636,19 @@ function flush_queued_effects(effects) {
/ * *
* This is similar to ` mark_reactions ` , but it only marks async / block effects
* so that these can re - run after another batch has been committed
* depending on ` value ` and at least one of the other ` sources ` , so that
* these effects can re - run after another batch has been committed
* @ param { Value } value
* @ param { Source [ ] } sources
* /
function mark _effects ( value ) {
function mark _effects ( value , sources ) {
if ( value . reactions !== null ) {
for ( const reaction of value . reactions ) {
const flags = reaction . f ;
if ( ( flags & DERIVED ) !== 0 ) {
mark _effects ( /** @type {Derived} */ ( reaction ) );
} else if ( ( flags & ( ASYNC | BLOCK _EFFECT ) ) !== 0 ) {
mark _effects ( /** @type {Derived} */ ( reaction ) , sources );
} else if ( ( flags & ( ASYNC | BLOCK _EFFECT ) ) !== 0 && depends _on ( reaction , sources ) ) {
set _signal _status ( reaction , DIRTY ) ;
schedule _effect ( /** @type {Effect} */ ( reaction ) ) ;
}
@ -639,6 +656,26 @@ function mark_effects(value) {
}
}
/ * *
* @ param { Reaction } reaction
* @ param { Source [ ] } sources
* /
function depends _on ( reaction , sources ) {
if ( reaction . deps !== null ) {
for ( const dep of reaction . deps ) {
if ( sources . includes ( dep ) ) {
return true ;
}
if ( ( dep . f & DERIVED ) !== 0 && depends _on ( /** @type {Derived} */ ( dep ) , sources ) ) {
return true ;
}
}
}
return false ;
}
/ * *
* @ param { Effect } signal
* @ returns { void }