通俗易懂地理解React Fiber

Fiber
是在React16+首次引入的,至今已经过了好几年了,那么你有了解过Fiber
吗?
Fiber是什么
在了解Fiber
是什么之前,首先了解一下在Fiber出现之前,React更新视图的原理:通过setState改变数据从而触发虚拟DOM去进行对比,对比结束后将再进行DOM更新。那么更新就会分成两部分:
- 数据更新,触发虚拟DOM比较
- 比较完成后更新真实DOM节点
当对比少的节点时使用这种方法时比较合理的,但是当我们一次更新有几百个甚至更多组件需要进行对比时,由于Diff是一个同步的方法,在进行对比时,由于JS单线程的原因,导致其他的事件都无法响应。
当在这个Diff的过程中如果有有通过Input输入信息,那么他将得不到响应,显然这样体验会非常不好。
针对这样的问题,React 16+中首次引入了React Fiber
,就是用于解决渲染复杂组件时产生的卡顿问题。
Fiber是如何解决问题的
Fiber的作用就是将Diff的工作分割成很多个块
,并分散到不同帧
中执行。同时也新增了可控制新更新和模块执行优先级的能力。
帧:浏览器帧是根据显示器的刷新率而决定的,比如刷新率为 120Hz,则为120帧/s 每帧的时间就为 1000/120 = 8.3ms
简单来说,Fiber的作用就是对Diff的过程进行拆解
,把复杂的Diff拆分成不同的执行块,再分布到不同的帧中执行。
Fiber执行过程
Fiber的结构
React在创建虚拟DOM树的同时也会创建与DOM树相同的一个Fiber树(Fiber Tree),Fiber Tree
是由Fiber Node
组成。 每个Fiber Node主要由三部分组成: return,children,sibling
return:指向父节点
children:指向子节点
sibling:指向兄弟节点
Fiber Node
有上面的三个指针,可以确保Diff在暂停之后可以从最后遍历的地方继续进行Diff。
Fiber执行顺序
Fiber Node
关于执行优先级相关的有两个参数:ExpirationTime
和childExpirationTime
ExpirationTime
:到期时间,用于判断该节点是否在下一时间片执行childExpirationTime
:快速确定子树中是否有不在等待的变化
Fiber通过Fiber Node的ExpirationTime
决定执行的优先级,不同节点的ExpriationTime
也可能不同,当当前时间超过ExpirationTime
时,此时的Fiber Node需要执行的优先级最高,所以,当过期时间越小,执行的优先级就越高
ExpirationTime有两种计算的方式:
computeInteractiveExpiration
: 交互事件的过期时间computeAsyncExpiration
: 异步更新的过期时间
Fiber更新
当我们在调用setState
时,React会将更新的信息放到Fiber的更新队列中,在等待一定的时间后,再将更新队列的信息合并更新到WorkInProgress Tree
中。
WorkInProgress Tree
: 在遍历Fiber Node
时创建的一颗树,一般情况下结构是与Fiber Node相同的,在更新是用于更新组件,更新完毕后会将数据同步到Fiber Tree中。所以在更新开始是,Fiber Tree与WorkInProgress Tree是结构是相同的。
调度
上文提到,Fiber是在浏览器空闲的时候进行Diff的,而判断浏览器是否空闲则是用浏览器提供的API来实现的,用到的API包括:requestIdleCallback 和 requestAnimationFrame
- requestIdleCallback: 当浏览器空闲时执行回调函数
- requestAnimationFrame: 浏览器在下次重绘之前调用指定的回调函数
当workInProgress Tree生成完之后,会将整颗树交给浏览器渲染到页面上。在这个渲染流程中又分为两步:调和阶段和提交阶段
- 调和阶段:指的是
workInProgress Tree
的生成阶段,这个时候的执行是可以被暂停和从暂停的地方重新开始的。 - 提交阶段:指树已经对比并更新完,交给浏览器去DOM生成的阶段,此阶段是不可中断的。
调度的过程如下:
workInProgressTree的生成过程
在介绍ExpirationTime
也提到过,通过ExpirationTime来判断优先级,递归生成workInProgressTree。
总结
Fiber是React为了解决组件嵌套是Diff时间过长导致造成卡顿而实现的一种数据结构,通过Fiber将Diff分块并分散到不同的时间片执行,从而解决Diff卡顿问题。
Fiber通过记录父节点,子节点和兄弟节点来保证中断可恢复的。Fiber Node的执行优先级是通过
ExpirationTime
决定Fiber调度过程分成
调和阶段
和提交阶段
,调和阶段可中断,而提交阶段则不能。