@@ -30,6 +30,7 @@ import {
30
30
enableSchedulingProfiler ,
31
31
enableScopeAPI ,
32
32
skipUnmountedBoundaries ,
33
+ disableSchedulerTimeoutInWorkLoop ,
33
34
} from 'shared/ReactFeatureFlags' ;
34
35
import ReactSharedInternals from 'shared/ReactSharedInternals' ;
35
36
import invariant from 'shared/invariant' ;
@@ -750,7 +751,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
750
751
751
752
// This is the entry point for every concurrent task, i.e. anything that
752
753
// goes through Scheduler.
753
- function performConcurrentWorkOnRoot ( root ) {
754
+ function performConcurrentWorkOnRoot ( root , didTimeout ) {
754
755
// Since we know we're in a React event, we can clear the current
755
756
// event time. The next update will compute a new event time.
756
757
currentEventTime = NoTimestamp ;
@@ -790,6 +791,19 @@ function performConcurrentWorkOnRoot(root) {
790
791
return null ;
791
792
}
792
793
794
+ // TODO: We only check `didTimeout` defensively, to account for a Scheduler
795
+ // bug where `shouldYield` sometimes returns `true` even if `didTimeout` is
796
+ // true, which leads to an infinite loop. Once the bug in Scheduler is
797
+ // fixed, we can remove this, since we track expiration ourselves.
798
+ if (!disableSchedulerTimeoutInWorkLoop && didTimeout ) {
799
+ // Something expired. Flush synchronously until there's no expired
800
+ // work left.
801
+ markRootExpired ( root , lanes ) ;
802
+ // This will schedule a synchronous callback.
803
+ ensureRootIsScheduled ( root , now ( ) ) ;
804
+ return null ;
805
+ }
806
+
793
807
let exitStatus = renderRootConcurrent(root, lanes);
794
808
795
809
if (
0 commit comments