Reprint please keep this part of the content, indicate the source. Pay attention to the public number “No.1 front end”, weekly fresh front end good posts push.

In addition, the front end team of Toutiao is looking forward to your joining

What is Fiber

1. Fiber

You’re all familiar with the concepts of Process and Thread. In computer science, there’s also a concept called Fiber, which means a thinner Thread than Thread, which means a more sophisticated mechanism for concurrent processing than Thread.

2. React Fiber

React Fiber is a re-implementation of the core algorithm to replace the original Stack Reconciler

Intuitive feelings: claudiopro. Making. IO/react – fiber…

3. Why does Stack reconsiler cause frame loss

<div>
   <Foo>
      <Bar />
   </Foo>
</div>
Copy the code

The above JSX code is compiled to be recursively called code. When the component tree is very deep, changes that need to be Diff at once can take a long time, resulting in longer script times. The React optimization is similar to using shouldComponentUpdate to skip the Diff of some components.

Second, the idea of Fiber optimization

1. The background

Basic structure of React

React is the reconsiler, and React-dom is the renderer. The scheduler is always determined by react itself, and the renderer can be controlled and contributed by the community. ReactNative, React-DOM, etc. Fiber is an optimization of Reconsiler.

2. The Fiber in detail

2.1 Generate Fiber nodes

React Element

When a template is passed to the JSX compiler, the React Element is eventually generated. This is the actual content returned by the React component’s Render method, not HTML

class ClickCounter {
    //...
    render() {
        return [
            React.createElement(
                'button',
                {
                    key: '1',
                    onClick: this.onClick
                },
                'Update counter'
            ),
            React.createElement(
                'span',
                {
                    key: '2'
                },
                this.state.count
            )
        ]
    }
}
Copy the code
[{$$typeof: Symbol(React. Element), type: 'button', key: "1", props: { children: 'Update counter', onClick: () => { ... } } }, { $$typeof: Symbol(react.element), type: 'span', key: "2", props: { children: 0 } } ]Copy the code

Fiber Nodes

A fiber node is a data structure that describes the work to be performed later, analogous to a frame in a call stack, in other words, a unit of work. The Fiber architecture also provides a convenient way to track, schedule, pause, and interrupt coordination processes.

When a React Element is first converted into fiber node, the React child Element will be from the React of extracting data and create a new fiber in createFiberFromTypeAndProps function. React will reuse the created fiber node in the subsequent update process and update the changed data from the React Element to the fiber node. React also removes some fiber nodes. For example, when the corresponding key attribute changes on the same level, or when the React Element returned by the Render method does not have an Element object corresponding to the fiber, the fiber is removed.

Since React creates a fiber for each React Element, these fiber nodes are connected to form a Fiber tree. In our case it looks like this

2.2 It is divided into the Reconciliation phase and the Commit phase

In the React in the Fiber, the process of an update will be done into shards, so it is entirely possible that an update task is not yet complete, will be another update process of higher priority interrupt, at that time, the high priority update task will be dealt with in priority, and low priority tasks do update will void, and then wait for the opportunity to start again.

As the update process can be interrupted, the React Fiber update process is divided into two phases: the first Phase Reconciliation Phase and the second Commit Phase.

In the Reconciliation Phase, React Fiber will figure out which DOM needs to be updated. This Phase can be interrupted. But when it comes to the second Commit Phase, it’s time to push through DOM updates without interruption.

requestIdleCallback

var  = .requestIdleCallback([, ])
Copy the code
  • Callback: () : A callback is a task that needs to be performed when it is idle and takes an object as an incoming parameter. [IdleDeadline] (https://developer.mozilla.org/en-US/docs/Web/API/IdleDeadline) objects include:

    • DidTimeout, a Boolean value indicating whether the task has timed out, is used in conjunction with timeRemaining

    • TimeRemaining (), which represents the remaining time of the current frame, can also be interpreted as how much time is left for the task

  • Options: Currently, options has only one parameter

    • timeout: If timeout is specified and has a positive value, and the callback has not been called by timeout milliseconds, then the callback will be enforced during the next idle period, although this will most likely have a negative impact on performance.
  • cancelIdleCallback

React implementation of requestIdleCallback

  1. Due to therequestIdleCallbackCompatibility is not particularly good

  1. Callbacks can only be called 20 times per second

Unable to meet the actual requirements, React implemented a version of it itself.

The core of implementing the requestIdleCallback function is: how many times do you call the callback method when the browser is idle and after rendering?

Perform multiple executions using requestAnimationFrame and setTimeout

The callback method for the requestAnimationFrame is executed before each redraw, and it also has a flaw: it does not execute when the page is in the background, so we need to remedy this situation

rAFID = requestAnimationFrame(function(timestamp) { // cancel the setTimeout localClearTimeout(rAFTimeoutID); callback(timestamp); }); RAFTimeoutID = setTimeout (function () {/ / timing is 100 milliseconds is a best practice localCancelAnimationFrame (rAFID); callback(getCurrentTime()); }, 100);Copy the code

Calculates whether the current frame is idle

In simple terms, if the current time is 5000 and the browser supports 60 frames, then one frame is approximately 16 milliseconds, then the next frame will be calculated as 5016 and the time will be determined whether the time is less than 5016.

Perform the task after rendering

Only the macro task will be performed first after rendering, so the macro task is what we do to implement this step.

However, there are many ways to generate a macro task and each has a priority, so we must choose the one with the highest priority in order to perform the task the fastest. In this case, we chose MessageChannel for the task, rather than setImmediate, because of the poor compatibility.

2.3 Scheduling process of Reconciliation

  • First, each task has its own priority, and higher-priority tasks interrupt lower-priority tasks

  • Before scheduling, determine if the current task is expired. If the task is expired, you do not need to schedule it, and then you can execute the expired task immediately after rendering

  • If the task has not expired, start the timer via requestAnimationFrame and call the callback method before redrawing. In the callback method, we first need to calculate the time of each frame and the time of the next frame, and then create a macro task to execute.

  • The macro task is called after rendering, during which we first need to determine if the current time is less than the next frame time. Anything less means we still have time for the task; If it is larger than that, it means that there is no idle time for the current frame. At this point, we need to determine whether a task has expired. If it has expired, we still need to execute the task. If it doesn’t expire, you’ll have to wait until the next frame to see if it works.

3. Overall process

  1. Initialize the render, generating the corresponding Fiber tree from the React Element

  2. The setState operation triggers the update

  3. Create a copy of workInProgress and enter the Reconciliation to perform the render update.

  4. Record the fiber nodes that have side effects and put them in a queue

  5. Complete the Reconciliation and enter the Commit phase. Take out the fiber node with side effects, access the node with side effects through the nextEffect attribute of the fiber node, and update it

4. On the life cycle

4.1 Declaration period for UNSAFE

  • [UNSAFE_]componentWillMount (deprecated)

  • [UNSAFE_]componentWillReceiveProps (deprecated)

  • getDerivedStateFromProps

  • shouldComponentUpdate

  • [UNSAFE_]componentWillUpdate (deprecated)

4.2 componentWillReceiveProps and getDerivedStateFromProps

WillXXX allows users to manipulate the DOM at will. Manipulating the DOM may reflow, which is something the authorities do not want to see. GetDerivedStateFromProps lets you set the new state in render. You basically return a new object, and it will set the state for you. Since this is a static method, you can’t manipulate instance, which prevents you from manipulating setState multiple times. There’s no REFs, and you don’t have a chance to manipulate the DOM. This way, the logic for getDerivedStateFromProps should be simple so that there are no errors, no errors, and no interruptions to the DFS process.

reference

  • React Components, Elements, and Instances

  • Reactjs.org/docs/design…

  • zhuanlan.zhihu.com/p/37095662

  • Segmentfault.com/a/119000002…

  • Segmentfault.com/a/119000001…