@@ -41,6 +41,7 @@ import {
41
41
enableSiblingPrerendering ,
42
42
enableComponentPerformanceTrack ,
43
43
enableYieldingBeforePassive ,
44
+ enableThrottledScheduling ,
44
45
} from 'shared/ReactFeatureFlags' ;
45
46
import ReactSharedInternals from 'shared/ReactSharedInternals' ;
46
47
import is from 'shared/objectIs' ;
@@ -2609,8 +2610,10 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
2609
2610
// can't trust the result of `shouldYield`, because the host I/O is
2610
2611
// likely mocked.
2611
2612
workLoopSync ( ) ;
2613
+ } else if ( enableThrottledScheduling ) {
2614
+ workLoopConcurrent ( includesNonIdleWork ( lanes ) ) ;
2612
2615
} else {
2613
- workLoopConcurrent ( ) ;
2616
+ workLoopConcurrentByScheduler ( ) ;
2614
2617
}
2615
2618
break ;
2616
2619
} catch ( thrownValue ) {
@@ -2649,10 +2652,27 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
2649
2652
}
2650
2653
2651
2654
/** @noinline */
2652
- function workLoopConcurrent ( ) {
2655
+ function workLoopConcurrent ( nonIdle : boolean ) {
2656
+ // We yield every other "frame" when rendering Transition or Retries. Those are blocking
2657
+ // revealing new content. The purpose of this yield is not to avoid the overhead of yielding,
2658
+ // which is very low, but rather to intentionally block any frequently occuring other main
2659
+ // thread work like animations from starving our work. In other words, the purpose of this
2660
+ // is to reduce the framerate of animations to 30 frames per second.
2661
+ // For Idle work we yield every 5ms to keep animations going smooth.
2662
+ if ( workInProgress !== null ) {
2663
+ const yieldAfter = now ( ) + ( nonIdle ? 25 : 5 ) ;
2664
+ do {
2665
+ // $FlowFixMe[incompatible-call] flow doesn't know that now() is side-effect free
2666
+ performUnitOfWork ( workInProgress ) ;
2667
+ } while ( workInProgress !== null && now ( ) < yieldAfter ) ;
2668
+ }
2669
+ }
2670
+
2671
+ /** @noinline */
2672
+ function workLoopConcurrentByScheduler ( ) {
2653
2673
// Perform work until Scheduler asks us to yield
2654
2674
while ( workInProgress !== null && ! shouldYield ( ) ) {
2655
- // $FlowFixMe[incompatible-call] found when upgrading Flow
2675
+ // $FlowFixMe[incompatible-call] flow doesn't know that shouldYield() is side-effect free
2656
2676
performUnitOfWork ( workInProgress ) ;
2657
2677
}
2658
2678
}
0 commit comments