浅入 React Fiber 及相关资料整理
fiber 作为一种数据结构,用于代表某些 worker,换句话说,就是一个 work 单元,通过 Fiber 的架构,提供了一种跟踪,调度,暂停和中止工作的便捷方式。
react fiber 及未来
异步渲染 Dan 提出的异步渲染的概念,异步渲染即在以异步的方式加载的同时给人以同步流程的体验,在老设备上,通过牺牲一些加载时间来获得一种流畅的体验。其实在 React@16 版本中,异步渲染默认是关闭的。
生命周期变更 在 react@16 版本中,虽然依旧支持之前的生命周期函数,但是官方已经说明在下个版本中会将废弃其中的部分,这么做的原因,主要是 reconciliation 的重写导致。在 render/reconciliation 的过程中,因为存在优先级和时间片的概念,一个任务很可能执行到一半就被其他优先级更高的任务所替代,或者因为时间原因而被终止。当再次执行这个任务时,是从头开始执行一遍,就会导致组件的某些 xxxwill 生命周期可能被多次调用而影响性能。
react@16 与其说是一个分水岭,不如说是一个过渡,react@17 才会是掀起风浪的那一个。
- 如何理解 React Fiber 架构? - 知乎
- React Fiber - 掘金
- 图解浏览器的基本工作原理 - 知乎
- React 16 Fiber源码速览 | Zindex’s blog
- 翻譯 React Fiber 現狀確認 – CYB – Medium
- 完全理解React Fiber | 黯羽轻扬
- A Cartoon Intro to Fiber
- blog/from-jsx-to-dom.md at master · xieyu/blog · GitHub
- Sneak Peek: Beyond React 16
- [译]深入React fiber 链表和DFS
- React Fiber 架构学习
- 司徒正美的 React Fiber架构
Stack reconciler 自顶向下的递归 diff,这个过程无法中断(持续占用主线程),那么主线程上的 layout、动画等周期性任务以及交互响应就无法立即得到处理。
Fiber reconciler 的思路是把渲染/更新过程(递归diff)按照时间分片拆分成一系列小任务,通过任务调度每次检查 fiber tree 上的一小部分,如有空闲时间则继续下一个任务,否则将暂停或终止执行任务,待主线程完成更高优先级任务后再继续。
fiber tree 即 Fiber 上下文的 vDOM tree,更新过程就是根据输入数据以及现有的 fiber tree 构造出新的fiber tree(workInProgress tree)。一些细致一点的概念如下:
DOM
真实DOM节点
-------
effect
每个workInProgress tree节点上都有一个effect list
用来存放diff结果
当前节点更新完毕会向上merge effect list(queue收集diff结果)
- - - -
workInProgress
workInProgress tree是reconcile过程中从fiber tree建立的当前进度快照,用于断点恢复
- - - -
fiber
fiber tree与vDOM tree类似,用来描述增量更新所需的上下文信息
-------
Elements
描述UI长什么样子(type, props)
Fiber reconciler
1. render/reconciliation
初次渲染的时候构建 fiber tree,后续state或props有变更,则以此为蓝本,以 fiber node 为工作单元,自顶向下逐节点构造 workInProgress tree(构建中的新fiber tree)
具体过程如下:
- 如果当前节点不需要更新,直接把子节点 clone 过来,跳到5,要更新的话打个 tag
- 更新当前节点状态(props, state, context等)
- 调用 shouldComponentUpdate,如若返回 false 则跳到5
- 调用 render() 获得新的子节点,并为子节点创建 fiber(创建过程会尽量复用现有 fiber,子节点增删也发生在这里)
- [标识位5] 如果没有 child fiber,该工作单元结束,把 effect list 归并 return,并把当前节点的 sibling 作为下一个工作单元,否则把 child 作为下一个工作单元
- 在工作单元工作结束,则看看任务调度有无更高优先级任务,否则继续
- 如果没有下一个工作单元了,则回到了 workInProgress tree 的根节点,第1阶段结束,进入pendingCommit状态
workloop 结束时,workInProgress tree 的根节点身上的 effect list 就是收集到的所有 side effect(因为每做完一个都向上归并),所以,构建 workInProgress tree 的过程就是 diff 的过程。
workInProgress tree 构造完毕,得到的就是新的 fiber tree,然后把 current 指针指向 workInProgress tree,丢掉旧的 fiber tree。这样做的好处:能够复用内部对象(fiber),节省内存分配、GC 的时间开销。
2. commit(该阶段不能打断)
- 处理 effect list,包括 3 种处理:更新DOM树、调用组件生命周期函数以及更新ref等内部状态
- 把所有的 DOM changes 的 patches 都 commit 到 DOM 树上
任务调度
diff 的粒度控制为一个fiber node,实际上就是按虚拟 DOM 节点拆,因为 fiber tree 是根据 v-DOM tree 构造出来的,树结构一模一样,只是节点数据信息有差异。
任务调度分两部分:工作循环 & 优先级机制。
工作循环是基本的任务调度机制,工作循环中每次处理一个任务(工作单元),处理完毕有一次喘息的机会,基本规则是:每个工作单元结束检查是否还有时间做下一个,没时间了就先“挂起”
优先级机制用来处理突发事件与优化次序。
中断/断点恢复
- 中断:检查当前正在处理的工作单元,保存当前成果(firstEffect, lastEffect),修改 tag 标记一下,迅速收尾并再开一个requestIdleCallback,下次有机会再做
- 断点恢复:下次再处理到该工作单元时,看tag是被打断的任务,接着做未完成的部分或者重做
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论