Skip to content

Commit aa4412e

Browse files
committed
Yield every other frame for Transition/Retry work
1 parent 33a25cb commit aa4412e

File tree

1 file changed

+23
-3
lines changed

1 file changed

+23
-3
lines changed

packages/react-reconciler/src/ReactFiberWorkLoop.js

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import {
4141
enableSiblingPrerendering,
4242
enableComponentPerformanceTrack,
4343
enableYieldingBeforePassive,
44+
enableThrottledScheduling,
4445
} from 'shared/ReactFeatureFlags';
4546
import ReactSharedInternals from 'shared/ReactSharedInternals';
4647
import is from 'shared/objectIs';
@@ -2610,8 +2611,10 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
26102611
// can't trust the result of `shouldYield`, because the host I/O is
26112612
// likely mocked.
26122613
workLoopSync();
2614+
} else if (enableThrottledScheduling) {
2615+
workLoopConcurrent(includesNonIdleWork(lanes));
26132616
} else {
2614-
workLoopConcurrent();
2617+
workLoopConcurrentByScheduler();
26152618
}
26162619
break;
26172620
} catch (thrownValue) {
@@ -2650,10 +2653,27 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
26502653
}
26512654

26522655
/** @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() {
26542674
// Perform work until Scheduler asks us to yield
26552675
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
26572677
performUnitOfWork(workInProgress);
26582678
}
26592679
}

0 commit comments

Comments
 (0)