Before talking about Fiber, let’s first understand the former Stack Reconciler of Fiber

Harmonic process and Diff algorithm

Also translated as harmonization, the process of harmonization is officially defined as follows:

Virtual DOM is a programming concept in which the UI is stored in memory in an idealized or Virtual representation and synchronized with the real DOM through libraries such as ReactDOM, a process called harmonization.

Generally speaking, it is the process of mapping virtual DOM to real DOM. Therefore, strictly speaking, the reconciliation process cannot be equalized with Diff. Reconciliation is the process of “making consistent”, while Diff is the process of “finding different”, and it is only a part of the process of “making consistent”.

However, in today’s public perception, when we talk about harmony, we are actually talking about Diff. In fact, such cognition has its rationality, because Diff is indeed the most representative link in the process of harmony. According to the different forms of realization of Diff, The reconciliation process is divided into “stack reconciliation” represented by React 15 and “Fiber reconciliation” since React 16.

Design idea of Diff strategy

The traditional calculation method is to compare tree nodes one by one through cyclic recursion. The algorithm complexity of this process is O(n^3). Later, the React team converted the complexity to O(n) based on some derivation at the design level.

  • If two components are of the same type, they will have the same DOM tree structure
  • A set of nodes at the same level can be uniquely identified by a key to maintain the stability of each node in different rendering processes.
  • There are not many cross-level operations between DOM nodes. Same-level operations are the mainstream

Key points of Diff algorithm

For the Diff algorithm, we only really need to understand the following three points:

  • The key point of Diff algorithm performance breakthrough lies in hierarchical comparison

    In consideration of the rule that there are not many cross-hierarchical operations between DOM nodes and same-hierarchical operations are the mainstream, the React Diff algorithm directly abandons cross-hierarchical node comparison and only compares nodes of the same hierarchy.

  • Nodes of the same type are necessary to continue Diff

    Combined with the rule that “if two components belong to the same type, they will have the same DOM tree structure”, we cannot directly deduce that “different types of components have different DOM structure”, but in most cases, this conclusion is valid. After all, the probability of encountering two components with exactly the same DOM structure but not the same type in real development is really low.

  • The key attribute is set to help us reuse nodes in the same layer as much as possible

    Key attempts to solve the reuse problem of nodes at the same level. On the official website, key is defined as follows:

    Key is used to help React identify what has been changed, added, or removed. The key needs to be written inside the element rendered in an array and given a stable value. Stability is important here, because React triggers a rerendering of the UI if the key changes. This is a very useful feature.

    Why did the React team bother with Fiber when Diff was already working so well? We start with the issues brought by Stack Reconciler as a starting point.

    Pre-knowledge – single-threaded JS and multi-threaded browsers

    As we all know, javascript is single-threaded, and browsers are multi-threaded. For multi-threaded browsers, in addition to dealing with JS threads, they also need to deal with event systems, timers, network requests and UI rendering threads responsible for DOM. The important thing is that javascript threads can manipulate the DOM, which means that our renderer thread and JS thread cannot work at the same time, and the other must be suspended while one is executing. Under this mechanism, if the JS thread occupies the main thread for a long time, the update of the rendering level will have to wait for a long time, and the user experience will be “stuck” if the interface is not updated for a long time.

    Why can produce “caton” such situation

    One of the unsolved problems posed by Stack Reconciler is the time-out of JavaScript on the main thread. Why is this a problem? Because the Stack Reconciler is a synchronous, recursive process.

    The synchronous recursive process means that once the update starts, it cannot be stopped. In essence, the stack harmonic Diff algorithm is actually a depth-first tree traversal process, which is fatal because it is synchronous and cannot be interrupted. When dealing with a relatively complex and large virtual DOM tree, the Stack Reconciler takes a long time to reconcile, which means that the JS thread can occupy the main thread for a long time, leading to the rendering stall we described above.

    How does Fiber solve the problem

    In computer science, we have threads and processes, and Fiber is a process that is even thinner than a thread. Fiber is designed to provide finer control over the rendering process. Here are the answers from the official website

    The purpose of The Fiber architecture, according to React, is to implement incremental rendering. In layman’s terms, incremental rendering is to divide a render task into multiple render tasks and scatter them over multiple frames. However, strictly speaking, incremental rendering is actually a means. Incremental rendering is designed to make tasks interruptible, recoverable, and give different priorities to different tasks, resulting in a smoother user experience.

    Here’s a comparison:

    Prior to Act16, the Render and update phases of React relied on a two-tier architecture

    As analyzed above, the Reconciler layer is responsible for comparing the changes between the old and new virtual DOM, and the Renderer layer is responsible for applying the changes to the view, and the process from Reconciler to Renderer is strictly synchronized.

    In React 16, in order to achieve “interruptibility” and “priority,” the two-tier architecture was changed to a three-tier architecture as shown below:

    This additional layer of architecture is called a “Scheduler,” which schedules the priority of updates.

    In this architectural pattern, the updated processing workflow looks like this: Every update task is first assigned a priority, and when it reaches the Reconciler, high-priority tasks are more quickly scheduled into the Reconciler layer. At this time, if a new update task reaches the Reconciler, the scheduler checks his priority first, and if it finds that his priority is greater than that of the current task, The Reconciler then interrupts tasks that are in the Reconciler’s layer, and the scheduler pushes new tasks into the Reconciler’s layer, and when the new tasks are completed, the tasks that were previously cut off are pushed back into the Reconciler’s layer and continue their rendering journey, which is called recoverable.

    The lifecycle impact of the Fiber architecture

    The life cycle of Act16 is divided into three phases:

    • Render phase: Pure and without side effects, may be suspended, terminated, or restarted by React.
    • Pre-commit phase: DOM can be read
    • Commit phase: You can use DOM, run side effects, and schedule updates

    React performs in-memory calculations to specify update points in the DOM tree, while React performs commit operations to execute updates generated in the RENDER phase.

    In React 16, render to commit looks like this:

    It can be seen that the impact of the old and new architectures on the React life cycle is mainly in the Render phase. In the Render phase, a huge update task is decomposed into work units, which have different priorities. React can interrupt and recover work units according to their priorities.