Fiber 的起源
最早的
Fiber
官方解释来源于2016 年 React 团队成员 Acdlite 的一篇介绍 (opens new window)。
从上一章的学习我们知道:
在React15
及以前,Reconciler
采用递归的方式创建虚拟 DOM,递归过程是不能中断的。如果组件树的层级很深,递归会占用线程很多时间,造成卡顿。
为了解决这个问题,React16
将递归的无法中断的更新重构为异步的可中断更新,由于曾经用于递归的虚拟 DOM 数据结构已经无法满足需要。于是,全新的Fiber
架构应运而生。
Fiber 的含义
Fiber
包含三层含义:
- 作为架构来说,之前
React15
的Reconciler
采用递归的方式执行,数据保存在递归调用栈中,所以被称为stack Reconciler
。React16
的Reconciler
基于Fiber节点
实现,被称为Fiber Reconciler
。 - 作为静态的数据结构来说,每个
Fiber节点
对应一个React element
,保存了该组件的类型(函数组件/类组件/原生组件…)、对应的 DOM 节点等信息。 - 作为动态的工作单元来说,每个
Fiber节点
保存了本次更新中该组件改变的状态、要执行的工作(需要被删除/被插入页面中/被更新…)。
Fiber 的结构
你可以从这里看到Fiber 节点的属性定义 (opens new window)。虽然属性很多,但我们可以按三层含义将他们分类来看
1 | function FiberNode( |
作为架构来说
每个 Fiber 节点有个对应的React element
,多个Fiber节点
是如何连接形成树呢?靠如下三个属性:
1 | // 指向父级Fiber节点 |
举个例子,如下的组件结构:
1 | function App() { |
对应的Fiber树
结构:
这里需要提一下,为什么父级指针叫做
return
而不是parent
或者father
呢?因为作为一个工作单元,return
指节点执行完completeWork
(本章后面会介绍)后会返回的下一个节点。子Fiber节点
及其兄弟节点完成工作后会返回其父级节点,所以用return
指代父级节点。
作为静态的数据结构
作为一种静态的数据结构,保存了组件相关的信息:
1 | // Fiber对应组件的类型 Function/Class/Host... |
作为动态的工作单元
作为动态的工作单元,Fiber
中如下参数保存了本次更新相关的信息,我们会在后续的更新流程中使用到具体属性时再详细介绍
1 | // 保存本次更新造成的状态改变相关信息 |
如下两个字段保存调度优先级相关的信息,会在讲解Scheduler
时介绍。
1 | // 调度优先级相关 |
注意
在 2020 年 5 月,调度优先级策略经历了比较大的重构。以expirationTime
属性为代表的优先级模型被lane
取代。详见这个 PR(opens new window)
如果你的源码中fiber.expirationTime
仍存在,请参照调试源码章节获取最新代码。
总结
本节我们了解了Fiber
的起源与架构,其中Fiber节点
可以构成Fiber树
。那么Fiber树
和页面呈现的DOM树
有什么关系,React
又是如何更新DOM
的呢?
我们会在下一节讲解。