Skip to content

Commit 8fd7b10

Browse files
committed
Yield every other frame for Transition/Retry work
1 parent 5580c99 commit 8fd7b10

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';
@@ -2609,8 +2610,10 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
26092610
// can't trust the result of `shouldYield`, because the host I/O is
26102611
// likely mocked.
26112612
workLoopSync();
2613+
} else if (enableThrottledScheduling) {
2614+
workLoopConcurrent(includesNonIdleWork(lanes));
26122615
} else {
2613-
workLoopConcurrent();
2616+
workLoopConcurrentByScheduler();
26142617
}
26152618
break;
26162619
} catch (thrownValue) {
@@ -2649,10 +2652,27 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
26492652
}
26502653

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

0 commit comments

Comments
 (0)