Fiber架构与双缓存机制
Fiber架构的基本概念
什么是Fiber
在React中,Fiber是一种用于描述组件树的数据结构,它代表了一种可中断的,可恢复的渲染任务。传统的渲染任务一旦开始,无法中断,直至渲染完成或发生错误,导致页面卡顿。Fiber将渲染任务分割成多个小任务,在渲染过程中可以中断,可重新排序调度任务,使React对浏览器的空闲时间进行了更充分的利用,提升了性能和用户体验。
Fiber树🌲
Fiber树的创建过程
- React根据JSX生成虚拟DOM树。
- 对每个虚拟DOM节点生成对应的Fiber节点,构建起Fiber树的层级结构。
- 执行初次渲染,React从根节点开始递归遍历Fiber树,执行组件的渲染,将组件渲染到DOM上。
Fiber树结构
Fiber节点结构
- 每个节点包含
- 指针(child、sibling、return)
- 属性(如DOM信息、任务调度信息)
- 状态信息
- 这些指针将节点连接成一个单链表结构、允许react通过循环遍历,遍历到每个节点。
Fiber树结构
- 以单链表形式组织,父节点指向第一个子节点,子节点通过sibling指针连接兄弟节点。
- 这种机制结构避免了传统树结构的递归遍历,减少栈溢出风险,提升性能。
Fiber树的更新
- 触发更新
- 生成新的虚拟DOM树
- 对比两棵虚拟DOM树的差异
- 根据协调算法的结果,React 会更新 Fiber 树的相应节点,执行组件的生命周期方法和渲染函数,将更新后的组件树渲染到 DOM 中。
协调算法
旧的协调算法
- 基于虚拟DOM树的比较
- 旧的协调算法通过深度遍历新旧虚拟DOM树,逐层比较节点的类型和属性。如果类型相同则更新属性,类型不同则销毁旧节点创建新的节点
- 递归处理子节点:
- 对于有子节点的节点,递归的对子节点进行比较,直至整个DOM树被比较完。这种递归方式,在处理深层嵌套结构时有栈溢出的风险
- 列表遍历优化
- 在处理列表时,旧的协调算法通过使用“key”属性来帮助识别元素的变化。通过唯一标识符"key",react能更准确的追踪元素变化,减少不必要的DOM操作
- 简单高效
- 旧的协调算法在大多数情况下能表现良好,但遇到复杂嵌套结构或长列表时,可能出现性能问题 一旦开始更新,就无法中断,直到所有节点都完成更新或者发生错误。这导致在更新过程中无法处理其他任务,从而影响了用户体验。
新的协调算法:增量渲染
增量渲染的核心思想:将渲染任务分割成多个小任务,并使用任务调度器动态的调度这些任务
增量渲染的好处:使得在更新过程中可以中断,并在下一个空闲时间片段内恢复,提高了渲染的灵活性和效率。增量渲染还为react引入了一些新的特性,如时间切片(Time Slicing)和任务优先级调度,使得React应用能够更好的适应不同的网络环境和设备性能。
时间切片
React通过将渲染任务切割成小的时间片,逐帧处理,确保用户界面能够快速响应用户操作。这种技术结合了任务优先级调度和可中断恢复机制,使得复杂的应用程序能够更高效地运行。
任务优先级调度
不同优先级的任务
// 无优先级任务
export const NoPriority = 0;
// 立即执行任务
export const ImmediatePriority = 1;
// 用户阻塞任务
export const UserBlockingPriority = 2;
// 正常任务
export const NormalPriority = 3;
// 低优先级任务
export const LowPriority = 4;
// 空闲执行任务
export const IdlePriority = 5;
在 React 中,任务被划分为不同的优先级,以便根据任务的重要性进行调度。通常情况下,React 将任务分为以下几个优先级:
- 同步任务:最高优先级的任务,通常用于处理用户交互事件和页面加载过程中的同步操作。
- 异步任务:中等优先级的任务,包括普通的更新任务和网络请求等异步操作。
- 空闲任务:最低优先级的任务,通常用于执行一些不紧急的任务,如日志记录或统计信息收集等。
调度器的工作方式
调度器会根据任务优先级和类型,动态的安排任务的执行顺序。调度器会监视浏览器的空闲时间,并根据当前在任务队列中的任务优先级决定在何时执行哪些任务。
Fiber架构的工作原理
双缓存机制
Fiber的双缓存机制是React16引入的核心优化技术之一,旨在提升渲染性能和用户体验。
双缓存机制的定义
Fiber双缓存机制通过维护两棵Fiber树来实现高效的渲染和更新
- Current Fiber树:当前屏幕上显示的真实UI对应的Fiber树。
- WorkInProgress Fiber树:正在内存中构建的新Fiber树,用于下一次的渲染
- 这两棵树通过alternate属性相互关联,即
currentFiber.alternate === workInProgressFiberworkInProgressFiber.alternate === currentFiber
React应用的根节点通过使current指针在不同Fiber树的rootFiber间切换来完成current Fiber树指向的切换。
双缓存机制的工作原理
- 首次渲染(Mount)
- 创建初始的Fiber Root节点,并生成初始的Current Fiber树
- 在内存中构建
workInProgressFiber树,并通过alternate属性与currentFiber树相关联
- 更新阶段(Update)
- 根据新的React节点与
currentFiber树生成新的workInProgressFiber树 - 通过深度优先遍历和Diff算法,比较新旧节点,生成更新标记(删除、移动、插入等)
- 构建完成后
workInProgressFiber树替换currentFiber树完成DOM更新
- 根据新的React节点与
- 交替切换
- 每次更新后
workInProgressFiber树成为新的currentFiber树,而旧的current树则成为下一次更新的workInProgress树
- 每次更新后
双缓存机制的优势
- 提升渲染性能:在内存中构建新的树,避免在屏幕上直接渲染导致闪烁和性能问题。
- 支持任务分片:将渲染任务切割成小块,逐帧处理,确保用户界面快速响应。
- 优先级调度:根据任务优先级决定执行性顺序,确保高优先级任务及时响应。
- 可恢复中断:允许在渲染过程中中断并恢复任务,优化用户体验。
Fiber双缓存机制的实现细节
- 交替属性:
workInProgressFiber树和currentFiber树通过alternate连接确保快速切换 - 根节点切换:React应用的根节点通过current指针在不同Fiber树的rootFiber之间切换,完成树的替换
- 任务调度:Fiber通过Scheduler API管理任务,确保渲染任务在不影响用户体验的情况下高效执行
手绘Fiber树构建流程图
graph TD
初始化根节点fiberRootNode和rootFiber--> 创建CurrentFiber--> 进入渲染阶段--> 在内存中构建WorkInProgressFiber树--> 进行Diffing比较新旧节点和复用旧节点--> 构建好新的WorkInProgressFiber树--> 进入体检阶段commit--> 渲染为真实DOM节点--> 替换CurrentFiber树fiberRootNode.current指向新的WorkInProgressFiber树--> 完成构建