0%

fiber架构原理

Fiber起源

React15之前,Reconciler采用递归创建虚拟DOM,递归过程不能中断,如果组件树的层级很深,递归会占用线程很多时间,造成卡顿

React16将递归的无法中断的更新重构为异步的可中断更新,由于曾经用于递归的虚拟DOM数据结构已经无法满足需要,全新的Fiber诞生

Fiber含义

1.作为架构,React15的Reconciler采用递归的方式执行,数据保存在递归调用栈中,所以被称为stack Reconciler,React 16 的Reconciler基于Fiber节点实现,被称为Fiber Reconciler

2.作为静态数据结构来说,每个Fiber节点对应于一个React element**,保存了该组件的类型**(函数组件/类组件/原生组件…),对应的DOM结点信息

3.对于动态的工作单元来说,每个Fiber结点保存了本次更新中该组件改变的状态,要执行的工作(需要被删除/被插入页面/被更新)

Fiber结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
function FiberNode (
tag: WorkTag,
pendingProps:mixed,
key: null|stirng,
mode: TypeofMode,
){
//作为静态数据结构的属性
this.tag = tag;
this.key=key;
this.elementType=null;
this.type=null;
this.stateNode=null;
//用于连接其他Fiber结点形成Fiber树
this.return=null;
this.child=null;
this.sibling=null;
this.index=0;
this.ref=null;
//作为动态的工作单元的属性
this.pendingProps=pendingProps;
this.memoizedProps=null;
this.updateQueue=null;
this.memoizedState=null;
this.dependencies=null;
this.mode=mode;
this.effectTag = NoEffect;
this.nextEffect = null;

this.firstEffect = null;
this.lastEffect = null;

// 调度优先级相关
this.lanes = NoLanes;
this.childLanes = NoLanes;

// 指向该fiber在另一次更新时对应的fiber
this.alternate = null;

}

作为架构来说

每个Fiber节点有个对应的React element,多个Fiber节点如何连接成树?

1
2
3
4
5
6
//指向父级Fiber结点
this.return=null;
//指向子Fiber节点
this.child=null;
//指向右边第一个兄弟Fiber结点
this.sibling=null;

作为静态的数据结构

保存了相关组件的信息

1
2
3
4
5
6
7
8
9
10
// Fiber对应组件的类型 Function/Class/Host...
this.tag = tag;
// key属性
this.key = key;
// 大部分情况同type,某些情况不同,比如FunctionComponent使用React.memo包裹
this.elementType = null;
// 对于 FunctionComponent,指函数本身,对于ClassComponent,指class,对于HostComponent,指DOM节点tagName
this.type = null;
// Fiber对应的真实DOM节点
this.stateNode = null;

作为动态的工作单元

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 保存本次更新造成的状态改变相关信息
this.pendingProps = pendingProps;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.dependencies = null;

this.mode = mode;

// 保存本次更新会造成的DOM操作
this.effectTag = NoEffect;
this.nextEffect = null;

this.firstEffect = null;
this.lastEffect = null;

保存优先级调度的相关信息

1
2
3
// 调度优先级相关
this.lanes = NoLanes;
this.childLanes = NoLanes;

Fiber架构的工作原理:

双缓存:

在内存中构建并直接替换的技术叫做双缓存

React使用双缓存来完成Fiber树的构建和替换——对应着DOM树的创建和更新

双缓存Fiber树

React中最多同时存在两棵Fiber树,当前屏幕显示内容对应的Fiber树称为current Fiber树,正在内存中构建的Fiber树称为workInProgress Fiber树,current Fiber树中的Fiber节点称为current fiber,workInProgress Fiber树中的Fiber节点被称为workInProgress fiber,它们通过alternate属性连接

1
2
currentFiber.alternate === workInProgressFiber;
workInProgressFiber.alternate === currentFiber;

React应用的根节点通过使用current指针在不同的Fiber树的rootFiber间切换来完成current Fiber树之间的切换

即当workInProgress Fiber树构建完成交给Renderer渲染在页面后,应用根结点的current指针指向workInProgress Fiber树,此时workInProgress Fiber树就变为current Fiber树

总结:

Reconciler工作的阶段称为render阶段,因为该阶段会调用组件的render方法

Renderer工作的阶段称为commit阶段,commit阶段会把renderer阶段提交的信息渲染到页面

render与commit阶段统称为work,即React在工作中,相对应的,如果任务正在Scheduler内调度,不属于work.