Understanding React Fiber: Design Principles, Execution Model, and Code Walkthrough
This article explains why React introduced the Fiber architecture, how it breaks rendering work into interruptible units, compares it with Vue's approach, and provides detailed code examples of Fiber's data structures, scheduling, traversal, and commit phases.
Fiber Design Philosophy
Fiber is a complete rewrite of React's core algorithm introduced in React 16+. It splits rendering work into small units to avoid blocking the main thread and to keep the UI responsive at 60 fps.
Why Fiber Is Needed
Browsers render frames in sync with the display refresh rate (≈60 Hz). When a task exceeds the 16 ms frame budget, the page becomes janky. A typical frame performs the following steps:
Process input events for immediate feedback.
Handle timers and execute their callbacks.
Process Begin Frame events (resize, scroll, media‑query changes, etc.).
Execute requestAnimationFrame callbacks.
Run layout calculations.
Perform paint operations.
Enter the idle period where requestIdleCallback tasks can run.
If any of these phases runs longer than 16 ms, the browser cannot render the next frame, causing noticeable lag.
Traditional Reconciliation vs. Fiber
Before Fiber, React used a recursive diff of the virtual DOM (called reconciliation) and updated the DOM synchronously, occupying the main thread for the entire update. This prevented the browser from handling high‑priority user events during long updates.
Fiber makes the reconciliation process interruptible. It breaks a large update into many small tasks, each of which can be paused, yielding control back to the browser, and later resumed. The mechanism relies on requestIdleCallback and requestAnimationFrame to schedule work during idle time.
Why Vue Does Not Use Fiber
Vue’s template‑based and watcher‑based system already splits updates into fine‑grained tasks, so a separate Fiber architecture is unnecessary.
React’s setState always starts from the root, creating a large task that benefits from Fiber’s splitting and interruption.
What Is a Fiber
A Fiber is both an execution unit and a data structure. Internally React implements the Fiber tree as a singly‑linked list where each node contains pointers to its first child, next sibling, and parent (return).
Fiber Node Example
{
type: any, // component constructor or HTML tag
key: null | string,
stateNode: any, // component instance or DOM node
child: Fiber | null,
sibling: Fiber | null,
return: Fiber | null,
tag: WorkTag,
nextEffect: Fiber | null,
updateQueue: mixed,
memoizedState: any,
pendingProps: any,
memoizedProps: any
}Linked‑List Update Queue
class Update {
constructor(payload, nextUpdate) {
this.payload = payload;
this.nextUpdate = nextUpdate;
}
}
class UpdateQueue {
constructor() {
this.baseState = null;
this.firstUpdate = null;
this.lastUpdate = null;
}
enqueueUpdate(update) {
if (!this.firstUpdate) {
this.firstUpdate = this.lastUpdate = update;
} else {
this.lastUpdate.nextUpdate = update;
this.lastUpdate = update;
}
}
forceUpdate() {
let state = this.baseState || {};
let cur = this.firstUpdate;
while (cur) {
const next = typeof cur.payload === 'function' ? cur.payload(state) : cur.payload;
state = { ...state, ...next };
cur = cur.nextUpdate;
}
this.firstUpdate = this.lastUpdate = null;
this.baseState = state;
return state;
}
}Scheduling with requestAnimationFrame and requestIdleCallback
Fiber uses requestAnimationFrame to run high‑priority work before the next paint, and requestIdleCallback to perform low‑priority tasks when the browser has spare time.
requestAnimationFrame Example
<body>
<div id="div"></div>
<button id="start">Start Animation</button>
</body>
<script>
const btn = document.getElementById('start');
const div = document.getElementById('div');
let start = 0;
const progress = () => {
div.style.width = div.offsetWidth + 1 + 'px';
div.innerHTML = div.offsetWidth + '%';
if (div.offsetWidth < 100) {
requestAnimationFrame(progress);
} else {
console.log('animation complete');
}
};
btn.addEventListener('click', () => {
div.style.width = '0';
requestAnimationFrame(progress);
});
</script>requestIdleCallback Example
let taskQueue = [
() => { console.log('task1 start'); console.log('task1 end'); },
() => { console.log('task2 start'); console.log('task2 end'); },
() => { console.log('task3 start'); console.log('task3 end'); }
];
function performUnitWork() { taskQueue.shift()(); }
function workloop(deadline) {
while ((deadline.timeRemaining() > 0 || deadline.didTimeout) && taskQueue.length) {
performUnitWork();
}
if (taskQueue.length) {
requestIdleCallback(workloop, { timeout: 1000 });
}
}
requestIdleCallback(workloop, { timeout: 1000 });Fiber Traversal Algorithm (Render Phase)
The render phase builds the effect list using a depth‑first (post‑order) traversal of the Fiber tree. The algorithm can be expressed as:
function beginWork(fiber) { console.log(`${fiber.key} start`); }
function completeUnitWork(fiber) { console.log(`${fiber.key} end`); }
function performUnitOfWork(fiber) {
beginWork(fiber);
if (fiber.child) return fiber.child;
while (fiber) {
completeUnitWork(fiber);
if (fiber.sibling) return fiber.sibling;
fiber = fiber.return;
}
}
function workloop(nextUnit) {
while (nextUnit) {
nextUnit = performUnitOfWork(nextUnit);
}
console.log('reconciliation phase finished');
}
workloop(rootFiber);Collecting the Effect List
During completion, each Fiber merges its children's effect lists and, if it has its own side effect, adds itself to the list via the nextEffect pointer.
function completeUnitOfWork(fiber) {
const parent = fiber.return;
if (parent) {
if (!parent.firstEffect) parent.firstEffect = fiber.firstEffect;
if (fiber.lastEffect) {
if (parent.lastEffect) parent.lastEffect.nextEffect = fiber.firstEffect;
parent.lastEffect = fiber.lastEffect;
}
if (fiber.effectTag) {
if (parent.lastEffect) parent.lastEffect.nextEffect = fiber;
else parent.firstEffect = fiber;
parent.lastEffect = fiber;
}
}
}Commit Phase
The commit phase applies all side effects from the effect list to the DOM. It is non‑interruptible.
function commitWork(fiber) {
if (!fiber) return;
const parentDOM = fiber.return.stateNode;
if (fiber.effectTag === 'INSERT') {
parentDOM.appendChild(fiber.stateNode);
} else if (fiber.effectTag === 'DELETE') {
parentDOM.removeChild(fiber.stateNode);
} else if (fiber.effectTag === 'UPDATE') {
if (fiber.type === 'TEXT') {
if (fiber.alternate.props.text !== fiber.props.text) {
fiber.stateNode.textContent = fiber.props.text;
}
}
}
fiber.effectTag = null;
}
function commitRoot() {
let next = workInProgressRoot.firstEffect;
while (next) {
commitWork(next);
next = next.nextEffect;
}
currentRoot = workInProgressRoot;
workInProgressRoot = null;
}Putting It All Together
The scheduler repeatedly calls workloop via requestIdleCallback. When there is no more work, it triggers commitRoot to flush the effect list and update the UI.
function workloop(deadline) {
while (nextUnitOfWork && deadline.timeRemaining() > 1) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
if (!nextUnitOfWork && workInProgressRoot) {
console.log('render phase finished');
commitRoot();
}
requestIdleCallback(workloop, { timeout: 1000 });
}Conclusion
This article provided an overview of React Fiber’s motivation, its execution model, and a step‑by‑step code implementation of the linked‑list data structure, scheduling, traversal, and commit phases. Readers are encouraged to explore the actual React source code for deeper details such as priority scheduling and task interruption.
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.
Taobao Frontend Technology
The frontend landscape is constantly evolving, with rapid innovations across familiar languages. Like us, your understanding of the frontend is continually refreshed. Join us on Taobao, a vibrant, all‑encompassing platform, to uncover limitless potential.
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.
