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