banner
SlhwSR

SlhwSR

热爱技术的一名全栈开发者
github
bilibili

fiber fragmentation

1. Problem#

The JavaScript engine and the page rendering engine are two threads that are mutually exclusive. When one thread is executing, the other thread can only be suspended and wait.

If the JavaScript thread occupies the main thread for a long time, the rendering updates will have to wait for a long time. The interface will not be updated for a long time, which will result in poor page responsiveness and users may experience lag.

This is also the problem faced by React 15's Stack Reconciler. When React renders a component, the entire process from start to finish is uninterrupted.

If the component is large, the JavaScript thread will continue to execute, and then wait until the entire VDOM tree is calculated before handing it over to the rendering thread.

This can cause some user interactions, animations, and other tasks to not be processed immediately, resulting in lag.

image

2. What is it#

React Fiber is a major change and optimization made by Facebook to React over a period of two years. It is a reimplementation of the core algorithm of React. It was confirmed by Facebook at the React Conf 2017 conference that React Fiber was released in React version 16.

In React, the following operations are mainly performed:

  • Each task is assigned a priority, and tasks with higher priority can interrupt tasks with lower priority. Then, the lower priority tasks are re-executed.
  • Asynchronous tasks are added, using the requestIdleCallback API to execute when the browser is idle.
  • The DOM diff tree is transformed into a linked list, where each DOM corresponds to two fibers (a linked list), and two queues correspond to them. This is all for finding interrupted tasks and re-executing them.

From an architectural perspective, Fiber is a rewrite of the React core algorithm (the reconciliation process).

From a coding perspective, Fiber is a data structure defined internally by React. It is a unit node of the Fiber tree structure, which is the virtual DOM in the new architecture of React 16.

A fiber is a JavaScript object that contains information about the element, its update operation queue, and its type. Its data structure is as follows:

type Fiber = {
  // Used to mark the WorkTag type of the fiber, mainly indicating the component type represented by the current fiber, such as FunctionComponent, ClassComponent, etc.
  tag: WorkTag,
  // The key in ReactElement
  key: null | string,
  // ReactElement.type, the first parameter passed to createElement
  elementType: any,
  // The type of the current node represented by the fiber
  type: any,
  // Represents the component instance corresponding to the current FiberNode
  stateNode: any,

  // Points to its parent in the Fiber node tree, used to return to the parent after processing this node
  return: Fiber | null,
  // Points to its first child node
  child: Fiber | null,
  // Points to its sibling node, the sibling node's return points to the same parent node
  sibling: Fiber | null,
  index: number,

  ref: null | (((handle: mixed) => void) & { _stringRef: ?string }) | RefObject,

  // Props object of the component during the current processing
  pendingProps: any,
  // Props after the last rendering is completed
  memoizedProps: any,

  // The queue where the Updates generated by the Fiber corresponding to this component are stored
  updateQueue: UpdateQueue<any> | null,

  // The state after the last rendering
  memoizedState: any,

  // A list that stores the contexts that this Fiber depends on
  firstContextDependency: ContextDependency<mixed> | null,

  mode: TypeOfMode,

  // Effect
  // Used to record Side Effects
  effectTag: SideEffectTag,

  // Single linked list for quickly finding the next side effect
  nextEffect: Fiber | null,

  // The first side effect in the subtree
  firstEffect: Fiber | null,
  // The last side effect in the subtree
  lastEffect: Fiber | null,

  // Represents the time point at which the task should be completed in the future, renamed as lanes in later versions
  expirationTime: ExpirationTime,

  // Quickly determine if there are changes in the subtree that are not waiting
  childExpirationTime: ExpirationTime,

  // Fiber version pool, records the fiber update process for easy recovery
  alternate: Fiber | null,
}

3. How to solve it#

Fiber splits the rendering update process into multiple subtasks, and only does a small part at a time. After completing a part of the task, it checks if there is any remaining time. If there is, it continues to the next task; if not, it suspends the current task and hands over the control to the main thread. When the main thread is not busy, it continues to execute.

It can be interrupted and resumed, and can also reuse the previous intermediate state. Different tasks are assigned different priorities. Each task update unit corresponds to a Fiber node of the React Element.

The implementation of the above approach is through the requestIdleCallback method.

The window.requestIdleCallback() method queues a function to be called during a browser's idle periods. This allows developers to perform background and low-priority work on the main event loop, without impacting latency-critical events such as animations and input response.

First, the tasks in React are divided into multiple steps and completed in batches. After completing a part of the task, the control is returned to the browser, allowing the browser to have time to render the page. When the browser is done with its busy tasks and has spare time, it continues with the unfinished tasks of React. This is a cooperative scheduling.

The implementation process is based on the Fiber node. As a static data structure, each Fiber node corresponds to a React element and saves information about the component type (function component/class component/native component, etc.) and the corresponding DOM node.

As a dynamic unit of work, each Fiber node saves the state changes and work to be performed for the component in the current update.

Each Fiber node has a corresponding React element, and multiple Fiber nodes build a tree based on the following three properties:

// Points to the parent Fiber node
this.return = null
// Points to the child Fiber node
this.child = null
// Points to the first sibling Fiber node on the right
this.sibling = null

These properties can be used to find the next execution target.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.