@@ -188,6 +188,8 @@ export const createScheduler = (
188188 let currentTime = performance . now ( ) ;
189189 const nextTick = createNextTick ( drainChoreQueue ) ;
190190 let flushTimerId : number | null = null ;
191+ let blockingChoresCount = 0 ;
192+ let currentChore : Chore | null = null ;
191193
192194 function drainInNextTick ( ) {
193195 if ( ! drainScheduled ) {
@@ -269,6 +271,7 @@ export const createScheduler = (
269271 if ( isTask ) {
270272 ( hostOrTask as Task ) . $flags$ |= TaskFlags . DIRTY ;
271273 }
274+
272275 const chore : Chore < T > = {
273276 $type$ : type ,
274277 $idx$ : isTask
@@ -339,6 +342,10 @@ This is often caused by modifying a signal in an already rendered component duri
339342 logWarn ( warningMessage ) ;
340343 DEBUG &&
341344 debugTrace ( 'schedule.SKIPPED host is not updatable' , chore , choreQueue , blockedChores ) ;
345+ // Decrement counter if this was a blocking chore that we're skipping
346+ if ( isRenderBlocking ( type ) ) {
347+ blockingChoresCount -- ;
348+ }
342349 return chore ;
343350 }
344351 }
@@ -367,8 +374,15 @@ This is often caused by modifying a signal in an already rendered component duri
367374 }
368375 }
369376
370- addChore ( chore , choreQueue ) ;
371- DEBUG && debugTrace ( 'schedule' , chore , choreQueue , blockedChores ) ;
377+ addChoreAndIncrementBlockingCounter ( chore , choreQueue ) ;
378+
379+ DEBUG &&
380+ debugTrace (
381+ isRenderBlocking ( type ) ? `schedule (blocking ${ blockingChoresCount } )` : 'schedule' ,
382+ chore ,
383+ choreQueue ,
384+ blockedChores
385+ ) ;
372386
373387 const runImmediately = ( isServer && type === ChoreType . COMPONENT ) || type === ChoreType . RUN_QRL ;
374388
@@ -426,6 +440,16 @@ This is often caused by modifying a signal in an already rendered component duri
426440 }
427441
428442 function applyJournalFlush ( ) {
443+ if ( blockingChoresCount > 0 ) {
444+ DEBUG &&
445+ debugTrace (
446+ `journalFlush.BLOCKED (${ blockingChoresCount } blocking chores)` ,
447+ null ,
448+ choreQueue ,
449+ blockedChores
450+ ) ;
451+ return ;
452+ }
429453 if ( ! isJournalFlushRunning ) {
430454 // prevent multiple journal flushes from running at the same time
431455 isJournalFlushRunning = true ;
@@ -503,7 +527,7 @@ This is often caused by modifying a signal in an already rendered component duri
503527 if ( vnode_isVNode ( blockedChore . $host$ ) ) {
504528 blockedChore . $host$ . blockedChores ?. delete ( blockedChore ) ;
505529 }
506- addChore ( blockedChore , choreQueue ) ;
530+ addChoreAndIncrementBlockingCounter ( blockedChore , choreQueue ) ;
507531 DEBUG && debugTrace ( 'schedule.UNBLOCKED' , blockedChore , choreQueue , blockedChores ) ;
508532 blockedChoresScheduled = true ;
509533 }
@@ -515,13 +539,12 @@ This is often caused by modifying a signal in an already rendered component duri
515539 }
516540 } ;
517541
518- let currentChore : Chore | null = null ;
519-
520542 try {
521543 while ( choreQueue . length ) {
522544 currentTime = performance . now ( ) ;
523545 const chore = ( currentChore = choreQueue . shift ( ) ! ) ;
524546 if ( chore . $state$ !== ChoreState . NONE ) {
547+ // Chore was already processed, counter already decremented in finishChore/handleError
525548 continue ;
526549 }
527550
@@ -535,6 +558,10 @@ This is often caused by modifying a signal in an already rendered component duri
535558 if ( vnode_isVNode ( chore . $host$ ) ) {
536559 chore . $host$ . chores ?. delete ( chore ) ;
537560 }
561+ // Decrement counter if this was a blocking chore that we're skipping
562+ if ( isRenderBlocking ( chore . $type$ ) ) {
563+ blockingChoresCount -- ;
564+ }
538565 continue ;
539566 }
540567
@@ -612,13 +639,40 @@ This is often caused by modifying a signal in an already rendered component duri
612639 if ( vnode_isVNode ( chore . $host$ ) ) {
613640 chore . $host$ . chores ?. delete ( chore ) ;
614641 }
615- DEBUG && debugTrace ( 'execute.DONE' , chore , choreQueue , blockedChores ) ;
642+
643+ // Decrement blocking counter if this chore was blocking journal flush
644+ if ( isRenderBlocking ( chore . $type$ ) ) {
645+ blockingChoresCount -- ;
646+ DEBUG &&
647+ debugTrace (
648+ `execute.DONE (blocking ${ blockingChoresCount } )` ,
649+ chore ,
650+ choreQueue ,
651+ blockedChores
652+ ) ;
653+ } else {
654+ DEBUG && debugTrace ( 'execute.DONE' , chore , choreQueue , blockedChores ) ;
655+ }
616656 }
617657
618658 function handleError ( chore : Chore , e : any ) {
619659 chore . $endTime$ = performance . now ( ) ;
620660 chore . $state$ = ChoreState . FAILED ;
621- DEBUG && debugTrace ( 'execute.ERROR' , chore , choreQueue , blockedChores ) ;
661+
662+ // Decrement blocking counter if this chore was blocking journal flush
663+ if ( isRenderBlocking ( chore . $type$ ) ) {
664+ blockingChoresCount -- ;
665+ DEBUG &&
666+ debugTrace (
667+ `execute.ERROR (blocking ${ blockingChoresCount } )` ,
668+ chore ,
669+ choreQueue ,
670+ blockedChores
671+ ) ;
672+ } else {
673+ DEBUG && debugTrace ( 'execute.ERROR' , chore , choreQueue , blockedChores ) ;
674+ }
675+
622676 // If we used the result as promise, this won't exist
623677 chore . $reject$ ?.( e ) ;
624678 container . handleError ( e , chore . $host$ ) ;
@@ -808,8 +862,25 @@ This is often caused by modifying a signal in an already rendered component duri
808862 }
809863 return null ;
810864 }
865+
866+ function addChoreAndIncrementBlockingCounter ( chore : Chore , choreArray : ChoreArray ) {
867+ if ( addChore ( chore , choreArray ) ) {
868+ blockingChoresCount ++ ;
869+ }
870+ }
811871} ;
812872
873+ export function addChore ( chore : Chore , choreArray : ChoreArray ) : boolean {
874+ const idx = choreArray . add ( chore ) ;
875+ if ( idx < 0 ) {
876+ if ( vnode_isVNode ( chore . $host$ ) ) {
877+ ( chore . $host$ . chores ||= new ChoreArray ( ) ) . add ( chore ) ;
878+ }
879+ return isRenderBlocking ( chore . $type$ ) ;
880+ }
881+ return false ;
882+ }
883+
813884function vNodeAlreadyDeleted ( chore : Chore ) : boolean {
814885 return ! ! ( chore . $host$ && vnode_isVNode ( chore . $host$ ) && chore . $host$ . flags & VNodeFlags . Deleted ) ;
815886}
@@ -833,11 +904,8 @@ export function addBlockedChore(
833904 }
834905}
835906
836- export function addChore ( chore : Chore , choreArray : ChoreArray ) {
837- const idx = choreArray . add ( chore ) ;
838- if ( idx < 0 && vnode_isVNode ( chore . $host$ ) ) {
839- ( chore . $host$ . chores ||= new ChoreArray ( ) ) . add ( chore ) ;
840- }
907+ function isRenderBlocking ( type : ChoreType ) : boolean {
908+ return type === ChoreType . NODE_DIFF || type === ChoreType . COMPONENT ;
841909}
842910
843911function choreTypeToName ( type : ChoreType ) : string {
0 commit comments