产生的原因
React15 通过递归的方式进行渲染,使用的是 JS 引擎自身的函数调用栈,它会一直执行到栈空为止。这个过程 react 称为reconcilation
(协调)。在reconcilation
期间,react 会一直占用浏览器资源,会导致用户触发的事件得不到响应。
Fiber 实现了自己的组件调用栈,它以链表的形式遍历组件树,可以灵活的暂停、继续和丢弃执行的任务。实现方式是使用了浏览器 requestIdlecallback 这一AP1。
但是react开发了一个 requestIdlecallback
react实现: 框架内可以分为三层:
- Virtual DOM层
- Reconciler 层 生命周期调用 ,进行diff运算等
- Renderer层 页面渲染
后续改动最大的 Reconciler 层,后续名称为 Fiber Reconciler
,之前的 Reconciler 被命名为Stack Reconciler
Stack Reconciler
的运行过程是不能被打断的,但是 Fiber Reconciler
每执行一端时间,就会将控制台交回浏览器,可以分段执行。这里的分段执行就需要 调度器Scheduling
来进行任务分配。
Fiber概念
react fiber是16版本之后的一种更新机制,使用链表取代了树,是一种fiber数据结构,其有三个指针,分别指向了父节点、子节点、兄弟节点,当中断的时候会记录下当前的节点,然后继续更新,它把组件渲染的工作分片,到时会主动让出渲染主线程。
Reconciliation (协调)
Reconciliation 是被普遍理解为"虚拟 DOM"的算法。当你渲染一个 React 应用程序时,一个描述应用程序的节点树被生成并保存在内存中。然后将该树刷新到渲染环境------ 例如,在浏览器应用程序的情况下,它被转换为一组 DOM 操作。当应用程序更新时(通常通过setState),会生成一棵新树。新树与之前的树进行比较,以计算更新渲染应用程序所需的操作。
Scheduling (调度)
确定什么时候应该执行某段代码。
调度核心理念便是:我们可以随心所欲的控制我们的代码。
Fiber做了很多切片任务,
详细调度可以看 React 的调度系统 Scheduler
Fiber Reconciler
Fiber Reconciler 运行会产生一个Fiber树,页面初始加载比较慢的原因是,也main渲染的同时,react内同时在生成Fiber树,加载较慢
运行的两个阶段:
- 阶段一: render/ reconciliation
- 阶段二:commit
阶段一:生成DOM树,得到需要更新的节点信息,这一步是渐进过程,可以被打断
阶段二:将需要更新的节点一次批量更新,这个过程不能被打断
Fiber 树
Fiber 是用链表结构遍历遍历组件树,并在页面初始加载阶段会创建Fiber树,
Fiber 是一个单链表树结构, 以 单链表 的数据结构, 以 后续遍历 的顺序,储存了 vdom树结构
Fiber结构
ini
function FiberNode(tag, pendingProps, key, mode) {
// Instance
this.tag = tag;
this.key = key;
this.elementType = null;
this.type = null;
this.stateNode = null;
// 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.contextDependencies = null;
this.mode = mode;
// Effects
this.effectTag = NoEffect;
this.nextEffect = null;
this.firstEffect = null;
this.lastEffect = null;
this.expirationTime = NoWork;
this.childExpirationTime = NoWork;
this.alternate = null;
if (enableProfilerTimer) {
this.actualDuration = Number.NaN;
this.actualStartTime = Number.NaN;
this.selfBaseDuration = Number.NaN;
this.treeBaseDuration = Number.NaN;
this.actualDuration = 0;
this.actualStartTime = -1;
this.selfBaseDuration = 0;
this.treeBaseDuration = 0;
}
// ...
}
每一个Fiber节点都是有子节点 child
、兄弟节点 sibling
和父节点 return
等属性
例如下方代码:
javascript
function App() {
return (
<div className="app">
<span>hello</span>, Fiber
</div>
);
}
形成的Fiber树:
为什么vue不需要Fiber?
React16中使用了 Fiber,但是 Vue 是没有 Fiber 的,为什么呢?原因是二者的优化思路不一样:
- Vue 是基于 template 和 watcher 的组件级更新,把每个更新任务分割得足够小,不需要使用到 Fiber 架构,将任务进行更细粒度的拆分
- React 是不管在哪里调用 setState,都是从根节点开始更新的,更新任务还是很大,需要使用到 Fiber 将大任务分割为多个小任务,可以中断和恢复,不阻塞主进程执行高优先级的任务
其中弧线为调用顺序。紫色为 beginWork、粉色为 completeWork。beginWork 是 "递" 的过程,而 comleteWork 则是 "归" 的过程。
参考链接:
这个没参考,留着后续看 理解react fiber原理