React 15
Reconciler协调器-----找出变化的组件Renderder渲染器-----同步渲染变化的组件
缺点
更新是同步不可中断的,用户会感知到页面的变化,一旦更新中单,会给用户造成不好的体验
React 16
Scheduler调度器-----调度任务的优先级,高优先级任务优先进入ReconcilerReconciler协调器-----找出变化的组件,打上标识Renderder渲染器-----异步可中断更新
Scheduler
调度器的功能并不是React独有或者最早提出的,其实在部分浏览器已经具备了调度器的功能
requestIdleCallback
React 为什么放弃使用requestIdleCallback
- 浏览器兼容问题
- 触发频率不稳定,受很多因素影响。比如当我们的浏览器切换tab后,之前tab注册的requestIdleCallback触发的频率会变得很低
- 没有调度优先级
Reconciler Renderder
React 16 是将Reconciler 协调器进行了重构
老版本React 是通过递归来更新dom的 Reconciler与Renderer 交替工作,会同步的更新DOM,给用户感知上的变化
新版本的React Reconciler与Renderer不再是交替工作,Reconciler会将需要更新的组件,打上标识,统一移交给Renderer,最后由渲染器统一渲染,这个过程的变化都是在js中,视图不会发生任何变化,用户是无法感知的。
这就是新版本 React 16 的异步可中断更新
Fiber
React内部实现的一套状态更新机制。支持任务不同优先级,可中断与恢复,并且恢复后可以复用之前的中间状态
其中每个任务更新单元为React Element对应的Fiber节点
虚拟DOM === Fiber
Fiber的出现
新版本的React 实现了异步可中断更新,那么老版本的不可中断更新的虚拟DOM结构已经不能满足新版本React对于虚拟DOM的需求,就出现了一种全新的架构---Fiber
Fiber的含义
-
架构: 老版本的React
Reconciler递归更新,被称为stack Reconciler新版本的ReactReconciler异步可中断更新,被称为Fiber Reconciler -
静态数据结构: 每个
Fiber节点保存了当前组件的类型,对应的DOM信息 -
动态数据结构: 每个
Fiber节点保存了本次更新改变的状态, 要执行的工作(增删改查)
Fiber的结构
function FiberNode(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
// 作为静态数据结构的属性
this.tag = tag; // 组件的类型??? 函数,类
this.key = key; // key值
this.elementType = null; //
this.type = null;
this.stateNode = null; // 真实DOM节点
// 用于连接其他Fiber节点形成Fiber树
this.return = null; // 指向父节点的Fiber
this.child = null; // 指向子节点的Fiber
this.sibling = null; // 指向同级的Fiber
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 中会存在两棵Fiber树
-
current Fiber当前展示在页面中的Fiber 树(虚拟DOM树) -
workInPorgress Fiber正在内存中构建的Fiber树 (触发更新时就会创建)
currentFiber.alternate === workInProgressFiber;
workInProgressFiber.alternate === currentFiber;
React 通过 current 指针切换不同的Fiber树的rootFiber间切换来完成current Fiber树指向的切换
更新流程
function App() {
const [num, add] = useState(0);
return (
<p onClick={() => add(num + 1)}>{num}</p>
)
}
ReactDOM.render(<App/>, document.getElementById('root'));
首次执行, 会创建出fiberRoot 和 rootFiber
fiberRoot 代表了整个应用的根节点
rootFiber 代表了当前组件的根节点
每个组件都会拥有自己的rootFiber,但是fiberRoot只会有一个
第一次更新
初次创建 rootFiber下没有任何的Fiber节点
由于是第一次render 所以在内存中创建workInPorgress Fiber
创建对应的DOM元素 通过return child sibling 进行连接,形成最新的workInPorgress Fiber
只有currentFiber的rootFiber 通过 alternate 连接了 workInPorgress Fiber的 rootFiber
更新阶段
在render的过程中,在内存中创建workInPorgress Fiber
新旧的Fiber 节点 通过alternate 连接
根据记录的更新信息,进行相对应的功能
render阶段结束,进入commmit阶段,用workInPorgress Fiber 替换 current Fiber 形成最新的current Fiber