react源码解析7.Fiber架构
视频解说(高效学习):点击学习
往期文章:
1.开篇介绍和面试题
2.react的设计理念
3.react源码架构
4.源码目录构造和调试
5.jsx&外围api
6.legacy和concurrent模式入口函数
7.Fiber架构
8.render阶段
9.diff算法
10.commit阶段
11.生命周期
12.状态更新流程
13.hooks源码
14.手写hooks
15.scheduler&Lane
16.concurrent模式
17.context
18事件零碎
19.手写迷你版react
20.总结&第一章的面试题解答
21.demo
Fiber的深度了解
react15在render阶段的reconcile是不可打断的,这会在进行大量节点的reconcile时可能产生卡顿,因为浏览器所有的工夫都交给了js执行,并且js的执行时单线程。为此react16之后就有了scheduler进行工夫片的调度,给每个task(工作单元)肯定的工夫,如果在这个工夫内没执行完,也要交出执行权给浏览器进行绘制和重排,所以异步可中断的更新须要肯定的数据结构在内存中来保留工作单元的信息,这个数据结构就是Fiber。
那么有了Fiber这种数据结构后,能实现哪些事件呢,
- 工作单元 工作合成 :Fiber最重要的性能就是作为工作单元,保留原生节点或者组件节点对应信息(包含优先级),这些节点通过指针的形似造成Fiber树
- 增量渲染:通过jsx对象和current Fiber的比照,生成最小的差别补丁,利用到实在节点上
- 依据优先级暂停、持续、排列优先级:Fiber节点上保留了优先级,能通过不同节点优先级的比照,达到工作的暂停、持续、排列优先级等能力,也为下层实现批量更新、Suspense提供了根底
- 保留状态:因为Fiber能保留状态和更新的信息,所以就能实现函数组件的状态更新,也就是hooks
Fiber的数据结构
Fiber的自带的属性如下:
//ReactFiber.old.js
function FiberNode(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
//作为动态的数据结构 保留节点的信息
this.tag = tag;//对应组件的类型
this.key = key;//key属性
this.elementType = null;//元素类型
this.type = null;//func或者class
this.stateNode = null;//实在dom节点
//作为fiber数架构 连接成fiber树
this.return = null;//指向父节点
this.child = null;//指向child
this.sibling = null;//指向兄弟节点
this.index = 0;
this.ref = null;
//用作为工作单元 来计算state
this.pendingProps = pendingProps;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.dependencies = null;
this.mode = mode;
//effect相干
this.effectTag = NoEffect;
this.nextEffect = null;
this.firstEffect = null;
this.lastEffect = null;
//优先级相干的属性
this.lanes = NoLanes;
this.childLanes = NoLanes;
//current和workInProgress的指针
this.alternate = null;
}
Fiber双缓存
当初咱们晓得了Fiber能够保留实在的dom,实在dom对应在内存中的Fiber节点会造成Fiber树,这颗Fiber树在react中叫current Fiber,也就是以后dom树对应的Fiber树,而正在构建Fiber树叫workInProgress Fiber,这两颗树的节点通过alternate相连.
function App() {
return (
<>
<h1>
<p>count</p> xiaochen
</h1>
</>
)
}
ReactDOM.render(<App />, document.getElementById("root"));
构建workInProgress Fiber产生在createWorkInProgress中,它能创立或者服用Fiber
//ReactFiber.old.js
export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
let workInProgress = current.alternate;
if (workInProgress === null) {//辨别是在mount时还是在update时
workInProgress = createFiber(
current.tag,
pendingProps,
current.key,
current.mode,
);
workInProgress.elementType = current.elementType;
workInProgress.type = current.type;
workInProgress.stateNode = current.stateNode;
workInProgress.alternate = current;
current.alternate = workInProgress;
} else {
workInProgress.pendingProps = pendingProps;//复用属性
workInProgress.type = current.type;
workInProgress.flags = NoFlags;
workInProgress.nextEffect = null;
workInProgress.firstEffect = null;
workInProgress.lastEffect = null;
//...
}
workInProgress.childLanes = current.childLanes;//复用属性
workInProgress.lanes = current.lanes;
workInProgress.child = current.child;
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
const currentDependencies = current.dependencies;
workInProgress.dependencies =
currentDependencies === null
? null
: {
lanes: currentDependencies.lanes,
firstContext: currentDependencies.firstContext,
};
workInProgress.sibling = current.sibling;
workInProgress.index = current.index;
workInProgress.ref = current.ref;
return workInProgress;
}
- 在mount时:会创立fiberRoot和rootFiber,而后依据jsx对象创立Fiber节点,节点连接成current Fiber树。
-
在update时:会依据新的状态造成的jsx(ClassComponent的render或者FuncComponent的返回值)和current Fiber比照形(diff算法)成一颗叫workInProgress的Fiber树,而后将fiberRoot的current指向workInProgress树,此时workInProgress就变成了current Fiber。fiberRoot:指整个利用的根节点,只存在一个
fiberRoot:指整个利用的根节点,只存在一个
rootFiber:ReactDOM.render或者ReactDOM.unstable_createRoot创立进去的利用的节点,能够存在多个。
咱们当初晓得了存在current Fiber和workInProgress Fiber两颗Fiber树,Fiber双缓存指的就是,在通过reconcile(diff)造成了新的workInProgress Fiber而后将workInProgress Fiber切换成current Fiber利用到实在dom中,存在双Fiber的益处是在内存中造成视图的形容,在最初利用到dom中,缩小了对dom的操作。
当初来看看Fiber双缓存创立的过程图:
-
mount时:
- 刚开始只创立了fiberRoot和rootFiber两个节点
- 而后依据jsx创立workInProgress Fiber:
- 把workInProgress Fiber切换成current Fiber
- 刚开始只创立了fiberRoot和rootFiber两个节点
-
update时
- 依据current Fiber创立workInProgress Fiber
- 把workInProgress Fiber切换成current Fiber
- 依据current Fiber创立workInProgress Fiber
发表回复