跪拜 Guibai
← All articles
React.js

How React's Fiber Architecture and Diff Algorithm Turn O(n³) Tree Comparisons Into 16ms Slices

By 为你学会写情书 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

A React app that stutters on large state updates is almost always hitting the limits of the old recursive reconciler or suffering from index-based keys. Understanding Fiber's time-slicing and Diff's key-matching rules gives a developer direct leverage over frame budgets and DOM churn — the difference between a 100 ms freeze and a 16 ms slice.

Summary

Stack Reconciler's recursive VDOM traversal blocks the main thread for tens or hundreds of milliseconds on large trees, freezing user interactions. Fiber replaces that recursion with a linked-list walk that yields control to the browser every unit of work, using `requestIdleCallback` to resume when the frame has idle time. A double-buffering scheme builds the next tree off-screen and commits DOM mutations atomically in a single uninterruptible phase.

The Diff algorithm makes three assumptions that drop complexity from O(n³) to O(n): cross-level node moves are rare (Tree Diff), keys identify stable nodes (Element Diff), and same-type components share structure (Component Diff). Without stable keys, a simple reorder triggers full destruction and recreation of every child node. With proper keys, the same reorder becomes four move operations with zero mounts or unmounts.

Together, Fiber answers "when to work" and Diff answers "what to change." The reconciliation loop processes one Fiber node per idle slice, marks side effects, and commits them in a single pass that never leaves the DOM in a half-updated state.

Takeaways
Stack Reconciler's recursive VDOM traversal is uninterruptible; a single setState on a large tree can block the main thread for 100+ ms.
Fiber replaces recursion with a linked-list walk using child, sibling, and return pointers, letting traversal pause and resume at any node.
React uses requestIdleCallback to process one Fiber node per idle frame slice, yielding control back to the browser between units.
A double-buffering scheme builds the workInProgress tree off-screen while the current tree stays visible; DOM mutations commit atomically in one uninterruptible phase.
Tree Diff compares only same-level nodes and destroys entire subtrees on type mismatch, trading cross-level move efficiency for a 90%+ complexity reduction.
Without stable keys, a child-list reorder triggers full destruction and recreation of every node; with unique keys, the same reorder becomes zero-cost moves.
Using array index as a key breaks Diff's identity tracking: inserting at the head causes every subsequent node to be destroyed and rebuilt.
The commit phase is always uninterruptible to guarantee DOM consistency; only the render/reconciliation phase can be sliced across frames.
Conclusions

React's performance model is a bet on frontend reality: cross-level DOM moves are so rare that destroying and recreating a moved subtree costs less than the algorithmic complexity of detecting the move.

The index-as-key anti-pattern is not a minor style issue — it defeats the entire Element Diff strategy and turns an O(n) update into O(n) full rebuilds, which is why it produces visibly broken component state.

Fiber's linked-list traversal is a direct response to JavaScript's single-threaded execution model; it does not make React faster in total work, but it prevents any single render from starving the event loop.

Double buffering means React never patches the DOM incrementally during reconciliation — the user sees either the old UI or the new UI, never an intermediate state, which eliminates an entire class of layout thrashing bugs.

Concepts & terms
Virtual DOM
A lightweight JavaScript object representation of the real DOM tree. React creates and compares these objects cheaply, then applies only the differences to the real DOM in batch.
Stack Reconciler
React's original reconciliation engine that traversed the Virtual DOM tree recursively. It was uninterruptible — once started, it blocked the main thread until the entire tree was processed.
Fiber
React's re-architected reconciler that represents each component as a Fiber node linked via child, sibling, and return pointers. This linked-list structure enables traversal to pause and resume, yielding the main thread between units of work.
Time Slicing
The technique of breaking a long rendering task into small chunks that each fit within a single frame's idle time (typically under 16 ms), using browser APIs like requestIdleCallback to schedule work without blocking user input.
Double Buffering
React builds the next Fiber tree (workInProgress) off-screen while the current tree remains displayed. Once complete, it swaps the trees and commits DOM mutations atomically, ensuring users never see a partially updated UI.
Tree Diff
The first layer of React's Diff strategy: comparison is performed only on nodes at the same level of the tree. If two nodes have different types, the entire old subtree is destroyed and a new one created, regardless of potential cross-level moves.
Element Diff
The second layer of React's Diff strategy: child nodes in a list are matched by their key prop. Stable, unique keys allow React to move existing DOM nodes rather than destroying and recreating them when list order changes.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗