Skip to content

Commit

Permalink
Yield every other frame for Transition/Retry work
Browse files Browse the repository at this point in the history
  • Loading branch information
sebmarkbage committed Dec 18, 2024
1 parent 5580c99 commit 8fd7b10
Showing 1 changed file with 23 additions and 3 deletions.
26 changes: 23 additions & 3 deletions packages/react-reconciler/src/ReactFiberWorkLoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
enableSiblingPrerendering,
enableComponentPerformanceTrack,
enableYieldingBeforePassive,
enableThrottledScheduling,
} from 'shared/ReactFeatureFlags';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import is from 'shared/objectIs';
Expand Down Expand Up @@ -2609,8 +2610,10 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
// can't trust the result of `shouldYield`, because the host I/O is
// likely mocked.
workLoopSync();
} else if (enableThrottledScheduling) {
workLoopConcurrent(includesNonIdleWork(lanes));
} else {
workLoopConcurrent();
workLoopConcurrentByScheduler();
}
break;
} catch (thrownValue) {
Expand Down Expand Up @@ -2649,10 +2652,27 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
}

/** @noinline */
function workLoopConcurrent() {
function workLoopConcurrent(nonIdle: boolean) {
// We yield every other "frame" when rendering Transition or Retries. Those are blocking
// revealing new content. The purpose of this yield is not to avoid the overhead of yielding,
// which is very low, but rather to intentionally block any frequently occuring other main
// thread work like animations from starving our work. In other words, the purpose of this
// is to reduce the framerate of animations to 30 frames per second.
// For Idle work we yield every 5ms to keep animations going smooth.
if (workInProgress !== null) {
const yieldAfter = now() + (nonIdle ? 25 : 5);
do {
// $FlowFixMe[incompatible-call] flow doesn't know that now() is side-effect free
performUnitOfWork(workInProgress);
} while (workInProgress !== null && now() < yieldAfter);
}
}

/** @noinline */
function workLoopConcurrentByScheduler() {
// Perform work until Scheduler asks us to yield
while (workInProgress !== null && !shouldYield()) {
// $FlowFixMe[incompatible-call] found when upgrading Flow
// $FlowFixMe[incompatible-call] flow doesn't know that shouldYield() is side-effect free
performUnitOfWork(workInProgress);
}
}
Expand Down

0 comments on commit 8fd7b10

Please sign in to comment.