说一下你理解的 React Fiber

💡 原文中文,约8000字,阅读约需19分钟。
📝

内容提要

React Fiber是React16之后的架构改进,将虚拟DOM和Diff的过程改为异步可中止的更新。React Fiber的核心是可中止、可恢复和优先级。它通过Fiber节点保存组件相关信息,并使用双缓存Fiber树实现DOM更新。React的Diff算法通过比较key和type来判断DOM节点是否可复用。

🔎

延伸解读

Fiber 架构如何解决同步渲染的卡顿问题

React 15 及之前,组件更新时虚拟 DOM 的创建和 Diff 是同步且不可中止的。如果组件树层级很深,Diff 会长时间占用浏览器 JS 线程,导致页面渲染被阻塞,出现卡顿。Fiber 架构将更新过程改为异步可中止,通过时间分片和优先级调度,让高优先级任务(如用户交互)可以中断低优先级任务,从而保持页面响应。

双缓存 Fiber 树:DOM 更新的核心机制

React 在内存中维护两棵 Fiber 树:当前屏幕上显示的 current Fiber 树和正在构建的 workInProgress Fiber 树。两棵树的节点通过 alternate 属性连接。每次更新时,React 基于 current 树构建新的 workInProgress 树,构建完成后在 commit 阶段一次性渲染到页面,并将 current 指针指向新树。这种双缓存机制使得更新过程可以随时中断和恢复,同时保证 DOM 更新的原子性。

Diff 算法的约束与 key 的作用

React 的 Diff 算法预设了三个约束:只对同级元素进行 diff、不同类型的元素会生成不同的树、使用 key 来保持稳定性。key 和 type 共同决定 DOM 节点是否可复用。如果 key 不同,React 会标记删除该节点;如果 key 相同但 type 不同,则销毁旧节点并创建新节点。使用 key 时,应避免使用 index 或随机值,否则可能导致不必要的节点重建或状态丢失。

多节点 Diff 的遍历过程与优化

多节点 Diff 分为两轮遍历。第一轮遍历按顺序比较新旧节点,如果 key 不同则立即跳出,如果 key 相同但 type 不同则标记删除并继续。第二轮遍历处理剩余节点:如果新旧都未遍历完,说明节点位置发生变化,React 会通过 lastPlacedIndex 变量判断节点是否需要移动。这种设计在保证正确性的同时,尽量复用已有 DOM 节点,减少性能开销。

❓

Q&A

React Fiber 的主要特点是什么?

React Fiber 的主要特点包括可中止、可恢复和优先级。

React Fiber 如何实现异步更新?

React Fiber 通过引入时刻分片和异步使命,允许高优先级任务中止低优先级任务,并使用 requestIdleCallback API 在浏览器闲暇时执行任务。

React Fiber 的双缓存 Fiber 树是如何工作的?

双缓存 Fiber 树包括 current Fiber 树和 workInProgress Fiber 树,current Fiber 树用于显示内容,workInProgress Fiber 树用于构建新的更新,更新完成后切换。

React 的 Diff 算法是如何判断 DOM 节点是否可复用的?

React 的 Diff 算法通过比较节点的 key 和 type 来判断 DOM 节点是否可复用,预设了只对同级元素进行 diff 和不同类型元素生成不同树的约束。

React Fiber 的架构分为哪几层?

React Fiber 的架构分为调度器、协调器和渲染器三层。

为什么 React 的 Diff 算法不支持双指针遍历?

React 的 Diff 算法不支持双指针遍历,因为同层级的 fiber 节点之间是通过 sibling 指针链接成的单链表,无法同时使用双指针。

🏷️

标签

➡️

继续阅读