Open Twlig opened 2 years ago
Reconciler采用递归的方式创建虚拟DOM,递归过程是不能中断的。如果组件树的层级很深,递归会占用线程很多时间,造成卡顿。
Reconciler
为了解决这个问题,React16将递归的无法中断的更新重构为异步的可中断更新,由于曾经用于递归的虚拟DOM数据结构已经无法满足需要。于是,全新的Fiber架构应运而生。
React16
Fiber
React Fiber可以理解为:
React Fiber
React内部实现的一套状态更新机制。支持任务不同优先级,可中断与恢复,并且恢复后可以复用之前的中间状态。
React
优先级
中间状态
Fiber包含三层含义:
React15
stack Reconciler
Fiber节点
Fiber Reconciler
React element
Fiber节点的属性定义,可以按三层含义将他们分类来看
function FiberNode( tag: WorkTag, pendingProps: mixed, key: null | string, mode: TypeOfMode, ) { // 作为静态数据结构的属性 // 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; // 用于连接其他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节点是如何连接形成树呢?靠如下三个属性:
// 指向父级Fiber节点 this.return = null; // 指向子Fiber节点 this.child = null; // 指向右边第一个兄弟Fiber节点 this.sibling = null;
举个例子,如下的组件结构:
function App() { return ( <div> i am <span>KaSong</span> </div> ) }
对应的Fiber树结构:
Fiber树
这里需要提一下,为什么父级指针叫做return而不是parent或者father呢?因为作为一个工作单元,return指节点执行完completeWork(本章后面会介绍)后会返回的下一个节点。子Fiber节点及其兄弟节点完成工作后会返回其父级节点,所以用return指代父级节点。
return
parent
father
completeWork
JSX 对象:即ClassComponent的render方法的返回结果,或FunctionComponent的调用结果。JSX对象中包含描述DOM节点的信息。
JSX 对象
ClassComponent
render
FunctionComponent
JSX对象
DOM节点
JSX是一种描述当前组件内容的数据结构,他不包含组件schedule、reconcile、render所需的相关信息。
JSX
比如如下信息就不包括在JSX中:
state
标记
这些内容都包含在Fiber节点中。
所以,在组件mount时,Reconciler根据JSX描述的组件内容生成组件对应的Fiber节点。
mount
在update时,Reconciler将JSX与Fiber节点保存的数据对比,生成组件对应的Fiber节点,并根据对比结果为Fiber节点打上标记。
update
当我们用canvas绘制动画,每一帧绘制前都会调用ctx.clearRect清除上一帧的画面。
canvas
ctx.clearRect
如果当前帧画面计算量比较大,导致清除上一帧画面到绘制当前帧画面之间有较长间隙,就会出现白屏。
为了解决这个问题,我们可以在内存中绘制当前帧动画,绘制完毕后直接用当前帧替换上一帧画面,由于省去了两帧替换间的计算时间,不会出现从白屏到出现画面的闪烁情况。
这种在内存中构建并直接替换的技术叫做双缓存 。
React使用“双缓存”来完成Fiber树的构建与替换——对应着DOM树的创建与更新。
DOM树
在React中最多会同时存在两棵Fiber树。当前屏幕上显示内容对应的Fiber树称为current Fiber树,正在内存中构建的Fiber树称为workInProgress Fiber树。
current Fiber树
workInProgress Fiber树
current Fiber树中的Fiber节点被称为current fiber,workInProgress Fiber树中的Fiber节点被称为workInProgress fiber,他们通过alternate属性连接。
current fiber
workInProgress fiber
alternate
currentFiber.alternate === workInProgressFiber; workInProgressFiber.alternate === currentFiber;
React应用的根节点通过使current指针在不同Fiber树的rootFiber间切换来完成current Fiber树指向的切换。
current
rootFiber
current Fiber
即当workInProgress Fiber树构建完成交给Renderer渲染在页面上后,应用根节点的current指针指向workInProgress Fiber树,此时workInProgress Fiber树就变为current Fiber树。
Renderer
每次状态更新都会产生新的workInProgress Fiber树,通过current与workInProgress的替换,完成DOM更新。
workInProgress
DOM
fiber架构由,fiberRoot整个项目的fiber架构根节点, rootFiber项目中每个函数组件或类组件的根节点组成。current Fiber树,当前页面上已渲染内容对应Fiber树。 workInProgress Fiber树,正在构建的Fiber树。fiberRoot的current会指向当前页面上已渲染内容对应Fiber树,即current Fiber树。触发更新时,构建完成workInProgress Fiber 树,通过alternate交换current Fiber和workInProgress Fiber。
fiberRoot
workInProgress Fiber 树
调用ReactDOM.render
进入reconcile的 Render阶段,深度优先遍历,构建一棵新的workInProgress Fiber 树。
进入renderer的 Commit阶段
调用this.setState,组件发生变化
进入Render阶段,采用深度优先遍历创建 workInProgress Fiber 树,workInProgress Fiber的创建可以复用current Fiber树对应的节点数据。
workInProgress Fiber
workInProgress Fiber 树在render阶段完成构建后进入commit阶段渲染到页面上。渲染完毕后,workInProgress Fiber 树变为current Fiber 树。
render阶段
commit阶段
current Fiber 树
commit
git commit
work
Scheduler
原文链接:https://react.iamkasong.com
前言
Reconciler
采用递归的方式创建虚拟DOM,递归过程是不能中断的。如果组件树的层级很深,递归会占用线程很多时间,造成卡顿。为了解决这个问题,
React16
将递归的无法中断的更新重构为异步的可中断更新,由于曾经用于递归的虚拟DOM数据结构已经无法满足需要。于是,全新的Fiber
架构应运而生。Fiber
React Fiber
可以理解为:React
内部实现的一套状态更新机制。支持任务不同优先级
,可中断与恢复,并且恢复后可以复用之前的中间状态
。Fiber
包含三层含义:React15
的Reconciler
采用递归的方式执行,数据保存在递归调用栈中,所以被称为stack Reconciler
。React16
的Reconciler
基于Fiber节点
实现,被称为Fiber Reconciler
。Fiber节点
对应一个React element
,保存了该组件的类型(函数组件/类组件/原生组件...)、对应的DOM节点等信息。Fiber节点
保存了本次更新中该组件改变的状态、要执行的工作(需要被删除/被插入页面中/被更新...)。Fiber的结构
Fiber节点的属性定义,可以按三层含义将他们分类来看
作为架构来说
每个Fiber节点有个对应的
React element
,多个Fiber节点
是如何连接形成树呢?靠如下三个属性:举个例子,如下的组件结构:
对应的
Fiber树
结构:JSX与Fiber节点
JSX 对象
:即ClassComponent
的render
方法的返回结果,或FunctionComponent
的调用结果。JSX对象
中包含描述DOM节点
的信息。JSX
是一种描述当前组件内容的数据结构,他不包含组件schedule、reconcile、render所需的相关信息。比如如下信息就不包括在
JSX
中:优先级
state
标记
这些内容都包含在
Fiber节点
中。所以,在组件
mount
时,Reconciler
根据JSX
描述的组件内容生成组件对应的Fiber节点
。在
update
时,Reconciler
将JSX
与Fiber节点
保存的数据对比,生成组件对应的Fiber节点
,并根据对比结果为Fiber节点
打上标记
。Fiber工作原理
什么是“双缓存”
当我们用
canvas
绘制动画,每一帧绘制前都会调用ctx.clearRect
清除上一帧的画面。如果当前帧画面计算量比较大,导致清除上一帧画面到绘制当前帧画面之间有较长间隙,就会出现白屏。
为了解决这个问题,我们可以在内存中绘制当前帧动画,绘制完毕后直接用当前帧替换上一帧画面,由于省去了两帧替换间的计算时间,不会出现从白屏到出现画面的闪烁情况。
这种在内存中构建并直接替换的技术叫做双缓存 。
React
使用“双缓存”来完成Fiber树
的构建与替换——对应着DOM树
的创建与更新。双缓存Fiber树
在
React
中最多会同时存在两棵Fiber树
。当前屏幕上显示内容对应的Fiber树
称为current Fiber树
,正在内存中构建的Fiber树
称为workInProgress Fiber树
。current Fiber树
中的Fiber节点
被称为current fiber
,workInProgress Fiber树
中的Fiber节点
被称为workInProgress fiber
,他们通过alternate
属性连接。React
应用的根节点通过使current
指针在不同Fiber树
的rootFiber
间切换来完成current Fiber
树指向的切换。即当
workInProgress Fiber树
构建完成交给Renderer
渲染在页面上后,应用根节点的current
指针指向workInProgress Fiber树
,此时workInProgress Fiber树
就变为current Fiber树
。每次状态更新都会产生新的
workInProgress Fiber树
,通过current
与workInProgress
的替换,完成DOM
更新。fiber架构
fiber架构由,fiberRoot整个项目的fiber架构根节点, rootFiber项目中每个函数组件或类组件的根节点组成。current Fiber树,当前页面上已渲染内容对应
Fiber树
。 workInProgress Fiber树,正在构建的Fiber树。fiberRoot
的current
会指向当前页面上已渲染内容对应Fiber树
,即current Fiber树
。触发更新时,构建完成workInProgress Fiber 树
,通过alternate交换current Fiber和workInProgress Fiber。mount
调用ReactDOM.render
进入reconcile的 Render阶段,深度优先遍历,构建一棵新的
workInProgress Fiber 树
。进入renderer的 Commit阶段
update
调用this.setState,组件发生变化
进入Render阶段,采用深度优先遍历创建
workInProgress Fiber 树
,workInProgress Fiber
的创建可以复用current Fiber树
对应的节点数据。workInProgress Fiber 树
在render阶段
完成构建后进入commit阶段
渲染到页面上。渲染完毕后,workInProgress Fiber 树
变为current Fiber 树
。总结:
Reconciler
工作的阶段被称为render
阶段。因为在该阶段会调用组件的render
方法。Renderer
工作的阶段被称为commit
阶段。就像你完成一个需求的编码后执行git commit
提交代码。commit
阶段会把render
阶段提交的信息渲染在页面上。render
与commit
阶段统称为work
,即React
在工作中。相对应的,如果任务正在Scheduler
内调度,就不属于work
。原文链接:https://react.iamkasong.com