@ -28,7 +28,7 @@ import * as e from '../errors.js';
import { flush _tasks } from '../dom/task.js' ;
import { DEV } from 'esm-env' ;
import { invoke _error _boundary } from '../error-handling.js' ;
import { old_values } from './sources.js' ;
import { mark_reactions , old_values } from './sources.js' ;
import { unlink _effect } from './effects.js' ;
import { unset _context } from './async.js' ;
@ -70,13 +70,15 @@ let last_scheduled_effect = null;
let is _flushing = false ;
let flushing _sync = false ;
export class Batch {
/ * *
* The current values of any sources that are updated in this batch
* They keys of this map are identical to ` this.#previous `
* @ type { Map < Source , any > }
* /
# current = new Map ( ) ;
current = new Map ( ) ;
/ * *
* The values of any sources that are updated in this batch _before _ those updates took place .
@ -156,7 +158,7 @@ export class Batch {
*
* @ param { Effect [ ] } root _effects
* /
# process ( root _effects ) {
process ( root _effects ) {
queued _root _effects = [ ] ;
/** @type {Map<Source, { v: unknown, wv: number }> | null} */
@ -169,7 +171,7 @@ export class Batch {
current _values = new Map ( ) ;
batch _deriveds = new Map ( ) ;
for ( const [ source , current ] of this . # current ) {
for ( const [ source , current ] of this . current ) {
current _values . set ( source , { v : source . v , wv : source . wv } ) ;
source . v = current ;
}
@ -300,7 +302,7 @@ export class Batch {
this . # previous . set ( source , value ) ;
}
this . # current . set ( source , source . v ) ;
this . current . set ( source , source . v ) ;
}
activate ( ) {
@ -346,49 +348,7 @@ export class Batch {
}
flush _effects ( ) {
var was _updating _effect = is _updating _effect ;
is _flushing = true ;
try {
var flush _count = 0 ;
set _is _updating _effect ( true ) ;
while ( queued _root _effects . length > 0 ) {
if ( flush _count ++ > 1000 ) {
if ( DEV ) {
var updates = new Map ( ) ;
for ( const source of this . # current . keys ( ) ) {
for ( const [ stack , update ] of source . updated ? ? [ ] ) {
var entry = updates . get ( stack ) ;
if ( ! entry ) {
entry = { error : update . error , count : 0 } ;
updates . set ( stack , entry ) ;
}
entry . count += update . count ;
}
}
for ( const update of updates . values ( ) ) {
// eslint-disable-next-line no-console
console . error ( update . error ) ;
}
}
infinite _loop _guard ( ) ;
}
this . # process ( queued _root _effects ) ;
old _values . clear ( ) ;
}
} finally {
is _flushing = false ;
set _is _updating _effect ( was _updating _effect ) ;
last _scheduled _effect = null ;
}
flush _effects ( ) ;
}
/ * *
@ -412,19 +372,8 @@ export class Batch {
this . # pending -= 1 ;
if ( this . # pending === 0 ) {
for ( const e of this . # render _effects ) {
set _signal _status ( e , DIRTY ) ;
schedule _effect ( e ) ;
}
for ( const e of this . # effects ) {
set _signal _status ( e , DIRTY ) ;
schedule _effect ( e ) ;
}
for ( const e of this . # block _effects ) {
set _signal _status ( e , DIRTY ) ;
schedule _effect ( e ) ;
for ( const source of this . current . keys ( ) ) {
mark _reactions ( source , DIRTY , false ) ;
}
this . # render _effects = [ ] ;
@ -487,6 +436,10 @@ export function flushSync(fn) {
e . flush _sync _in _effect ( ) ;
}
var prev _flushing _sync = flushing _sync ;
flushing _sync = true ;
try {
var result ;
const batch = Batch . ensure ( false ) ;
@ -501,6 +454,7 @@ export function flushSync(fn) {
flush _tasks ( ) ;
if ( queued _root _effects . length === 0 ) {
// TODO this might need adjustment
if ( batch === current _batch ) {
batch . flush ( ) ;
}
@ -514,6 +468,57 @@ export function flushSync(fn) {
batch . flush _effects ( ) ;
}
} finally {
flushing _sync = prev _flushing _sync ;
}
}
function flush _effects ( ) {
var was _updating _effect = is _updating _effect ;
is _flushing = true ;
try {
var flush _count = 0 ;
var batch = /** @type {Batch} */ ( current _batch ) ;
set _is _updating _effect ( true ) ;
while ( queued _root _effects . length > 0 ) {
if ( flush _count ++ > 1000 ) {
if ( DEV ) {
var updates = new Map ( ) ;
for ( const source of batch . current . keys ( ) ) {
for ( const [ stack , update ] of source . updated ? ? [ ] ) {
var entry = updates . get ( stack ) ;
if ( ! entry ) {
entry = { error : update . error , count : 0 } ;
updates . set ( stack , entry ) ;
}
entry . count += update . count ;
}
}
for ( const update of updates . values ( ) ) {
// eslint-disable-next-line no-console
console . error ( update . error ) ;
}
}
infinite _loop _guard ( ) ;
}
batch = /** @type {Batch} */ ( current _batch ) ;
batch . process ( queued _root _effects ) ;
old _values . clear ( ) ;
}
} finally {
is _flushing = false ;
set _is _updating _effect ( was _updating _effect ) ;
last _scheduled _effect = null ;
}
}
function infinite _loop _guard ( ) {
@ -545,6 +550,7 @@ function flush_queued_effects(effects) {
if ( ( effect . f & ( DESTROYED | INERT ) ) === 0 ) {
if ( is _dirty ( effect ) ) {
var wv = write _version ;
var current _size = /** @type {Batch} */ ( current _batch ) . current . size ;
update _effect ( effect ) ;
@ -568,6 +574,22 @@ function flush_queued_effects(effects) {
// if state is written in a user effect, abort and re-schedule, lest we run
// effects that should be removed as a result of the state change
if ( write _version > wv && ( effect . f & USER _EFFECT ) !== 0 ) {
// Work needs to happen in a separate batch, else prior sources would be mixed with
// newly updated sources, which could lead to infinite loops when effects run over and over again.
// We need to bring over the just written sources though to correctly mark the right reactions as dirty.
var old _batch = /** @type {Batch} */ ( current _batch ) ;
batches . delete ( old _batch ) ;
current _batch = null ;
var new _batch = Batch . ensure ( ! flushing _sync ) ;
var current _idx = 0 ;
// We're taking advantage of the spec here which says that entries in a Map are traversed by insertion order
for ( const source of old _batch . current ) {
if ( current _idx >= current _size ) {
new _batch . capture ( source [ 0 ] , source [ 1 ] ) ;
}
current _idx ++ ;
}
i ++ ;
break ;
}
}