react 运行时存在 3 种实例。
- DOM 真实 DOM 节点
- Instance React 维护的 vDOM
- Element 描述 UI 长什么样子 (type,props)
在首次渲染过程中构建出 vDOM tree,后续需要更新时 (setState()),diff vDOM tree 得到 DOM change,并把 DOM change 应用(patch)到 DOM 树。
Fiber 之前的 reconciler (被称为 Stack reconciler)自顶向下地递归 mount/update,无法中断(持续占用主线程)。
Fiber 解决这个问题的思路是把渲染/更新过程(递归 diff )拆分成一系列小任务,每次检查树上的一小部分,做完看是否还有时间继续下一个任务,有的话继续,没有则把自己挂起,主线程不忙的时候再继续。
增量更新需要更多的上下文信息,因此扩展出了 fiber tree (即 Fiber 上下文的 vDOM tree ),更新过程就是根据输入数据以及现有的 fiber tree 构造出新的 fiber tree (workInProgress tree)。
Instance 层新增了
- effect:1、每个 workInProgress tree 节点上都有一个 effect list;2、用来存放 diff 结果;3、当前节点更新完毕会向上 merge effect list (queue 收集 diff 结果)
- workInProgress:workInProgress tree 是 reconcile 过程中从 fiber tree 建立的当前进度快照,用于断点恢复。
- fiber:fiber tree 与 vDOM tree 类似,用来描述增量更新所需的上下文信息。
fiber tree 上各节点的主要结构(每个节点称为 fiber )如下:
{
stateNode,
child,
return,
sibling,
...
}
reconcile 过程分为 2 个阶段(phase):
- (可中断)render / reconciliation 通过构造 workInProgress tree 得出 change
- (不可中断)commit 应用这些 DOM change
commit:
- 处理 effect list (包括 3 种处理:更新 DOM 树、调用组件生命周期函数以及更新 ref 等内部状态)
- 出队结束,第 2 阶段结束,所有更新都 commit 到 DOM 树上。
生命周期 hook
第 1 阶段 render / reconciliation
- componentWillMount
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
第 2 阶段 commit
- componentDidMount
- componentDidUpdate
- componentWillUnmount
第 1 阶段的生命周期函数可能会被多次调用。
Fiber 是一种 LinkedList 的结构。Stack 是 tree 的结构,沿着树状层级结构向下处理。Fiber 则是依照 return、child 及 sibling 的顺序来针对该 ReactElement 做处理。
Fiber 的排程
Fiber 共有 beginWork、completeWork 及 commitWork 三种阶段。beginWork 会执行 component 实例化,调用 component 的 render() 方法,以及进行 shouldComponentUpdate() 结果比较。
github 关于 fiber 的 demo:
https://github.com/Vxee/react-async-mode
参考链接:
http://www.ayqy.net/blog/dive-into-react-fiber/