How Browser Rendering and React Fiber Work Together to Prevent Frame Drops
This article explains the fundamentals of browser rendering, frame lifecycle, and dropped‑frame issues, then demonstrates how React Fiber and the requestIdleCallback API can be used to split heavy tasks, improve concurrency, and keep UI interactions smooth.
Browser Rendering
To better understand React Fiber, we first review how the browser renderer works.
1. Rendering Frames
A frame is a single static image in an animation. Frame rate (frames per second) is the number of frames displayed each second. Frame duration is the time a frame stays on screen. A dropped frame occurs when a frame takes longer than the average duration.
Typical browser refresh rate is 60 Hz, so a frame must be rendered within 16.67 ms (1 s / 60).
If rendering exceeds this time, the user perceives stutter, i.e., a dropped frame.
1.2 Frame Lifecycle
Simple description of a frame's lifecycle:
1. Frame starts.
2. Main thread:
- Event Handlers: UI events such as input, click, wheel.
- RAF: Execute requestAnimationFrame callbacks.
- DOM Tree: Parse HTML and build the DOM tree; changes trigger this flow again.
- CSS Tree: Build CSS tree, producing the Render Tree.
- Layout: Compute position and size for all elements.
- Paint: Fill pixels (color, text, borders, etc.).
- Composite: Send drawing commands to the compositor thread.
- RequestIdleCallback: If the frame still has idle time, execute its callback.
3. Compositor thread:
- Raster: Split work into chunks, send to raster thread, which creates bitmaps and notifies the GPU to refresh the frame.
4. Frame ends.1.3 Dropped‑Frame Experiment
When a frame takes longer than 16 ms, the animation feels janky.
Demo: https://linjiayu6.github.io/FE-RequestIdleCallback-demo/
Example of a synchronous task that blocks the main thread:
const bindClick = id => {
element(id).addEventListener('click', Work.onSyncUnit);
};
bindClick('btnA');
bindClick('btnB');
bindClick('btnC');
var Work = {
unit: 10000,
onOneUnit: function() { for (var i = 0; i <= 500000; i++) {} },
onSyncUnit: function() {
let _u = 0;
while (_u < Work.unit) {
Work.onOneUnit();
_u++;
}
}
};1.4 Solving Dropped Frames
JavaScript execution consumes rendering time. To keep animations smooth, we can:
Process low‑priority work during idle time using requestIdleCallback .
Break heavy tasks into smaller steps.
(Optionally) Use Web Workers.
window.requestIdleCallback() queues a function to run during the browser's idle periods, allowing background work without delaying high‑priority events like animation and input.
Idle‑time experiment:
const bindClick = id => {
element(id).addEventListener('click', Work.onAsyncUnit);
};
bindClick('btnA');
bindClick('btnB');
bindClick('btnC');
var Work = {
unit: 10000,
onOneUnit: function() { for (var i = 0; i <= 500000; i++) {} },
onAsyncUnit: function() {
const FREE_TIME = 1;
let _u = 0;
function cb(deadline) {
while (_u < Work.unit && deadline.timeRemaining() > FREE_TIME) {
Work.onOneUnit();
_u++;
}
if (_u >= Work.unit) return;
window.requestIdleCallback(cb);
}
window.requestIdleCallback(cb);
}
};2. Limitations of React 15 Architecture
React 15 uses a recursive depth‑first traversal of the component tree, which blocks the main thread until the entire tree is processed.
class A extends React.Component {
render() {
return (
<div id="app">
<h1></h1>
<p></p>
<h2></h2>
<h3></h3>
</div>
);
}
}This approach leads to dropped frames when the tree is large or when heavy synchronous work is performed.
2.1 Why It Happens
The problem is analogous to the frame‑dropping experiment: a long‑running task occupies the call stack, preventing higher‑priority work.
2.2 Process and Code Analysis
Key functions in the old reconciler:
function workLoopSync() {
while (workInProgress !== null) {
performUnitOfWork(workInProgress);
}
}
function performUnitOfWork(unitOfWork) {
let next = beginWork();
if (next === null) {
completeUnitOfWork(unitOfWork);
} else {
workInProgress = next;
}
}3. Summary of Findings
React 15 processes updates via recursion, which monopolizes the main thread, causing visual stutter when the work exceeds the 16 ms frame budget.
4. Abstract Problem
When a low‑priority task runs, a higher‑priority task may be delayed, leading to inefficient scheduling.
5. Core Concerns
5.1 Concurrency & Scheduler
Concurrency means the ability to handle higher‑priority work while pausing lower‑priority tasks. The scheduler decides when to resume paused work.
5.2 Call Stack vs. Virtual Stack Frame
The traditional call stack cannot be paused; React implements a virtual stack frame (Fiber) to allow interruption and later resumption.
5.3 React 16+ Architecture
React 16 introduces Fiber, a data structure with three layers: instance properties, build properties (return, child, sibling), and work properties (effects, lanes).
5.4 Fiber Data Structure
Example of a simple Fiber node:
<div id="linjiayu">123</div>
<script type="text/babel">
const App = () => {
const [sum, setSum] = React.useState(0);
return (
<div id="app 1">
<h1 id="2-1 h1">标题 h1</h1>
<ul id="2-2 ul">
<li id="3-1 li" onClick={() => setSum(d => d + 1)}>点击 h2</li>
<li id="3-2 li">{sum}</li>
</ul>
<h3 id="2-3 h3">标题 h3</h3>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('linjiayu'));
</script>5.5 Work Loop
Two variants exist:
// Synchronous work loop
function workLoopSync() {
while (workInProgress !== null) {
performUnitOfWork(workInProgress);
}
}
// Concurrent (interruptible) work loop
function workLoopConcurrent() {
while (workInProgress !== null && !shouldYield()) {
performUnitOfWork(workInProgress);
}
}The scheduler maintains a task queue, executes tasks until time runs out or a higher‑priority task arrives, then yields back to the browser.
6. Small Summary
To achieve concurrency, React rewrites the core using Fiber nodes.
The traditional call stack cannot be paused; Fiber provides virtual stack frames.
Fiber enables scheduling, allowing tasks to be split, paused, and resumed based on priority.
The scheduler orchestrates asynchronous, interruptible work.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
