Fiber 架构工作原理

什么是 “双缓存”?

“双缓存” 是一种常见的图形处理技术,用于在图像渲染中实现平滑的、无闪烁的更新效果。它通过使用两个缓冲区(即两块内存区域)来完成。其中一个缓冲区用于显示图像,而另一个缓冲区则用于在后台进行图像的更新和绘制。当更新完成后,通过交换两个缓冲区的引用,以实现无缝的切换和更新。

在图形处理中使用双缓存的好处包括:

  1. 无闪烁:通过在后台缓冲区进行绘制,然后将绘制结果一次性地切换到显示缓冲区,可以避免在图像更新过程中的闪烁问题。这对于实时图形、动画和视频等应用非常重要。
  2. 平滑更新:使用双缓冲可以实现平滑的更新效果。在后台缓冲区进行绘制和更新,然后在更新完成后将其切换到显示缓冲区,可以避免直接在显示缓冲区上进行绘制和修改,从而减少了可能出现的可见的渲染中间状态。
  3. 减少渲染延迟:使用双缓冲可以减少渲染延迟。由于绘制和更新发生在后台缓冲区,因此可以在绘制完成后立即切换到显示缓冲区,从而减少了等待绘制完成的时间,提高了渲染效率和响应时间。

双缓存技术在图形处理、动画、视频播放和游戏开发等领域得到广泛应用。在图形库、操作系统和桌面应用程序中,双缓存被用于实现平滑的图像渲染和交互效果。在前端开发中,双缓存也被广泛应用于图形绘制和动画效果的实现,以提供更好的用户体验。

React 使用 “双缓存” 来完成 Fiber树的构建与替换 —— 对应着 DOM树的创建与更新。

双缓存 Fiber 树

React 中最多会同时存在两棵 Fiber树。当前屏幕上显示内容对应的 Fiber树称为 current Fiber树,正在内存中构建的 Fiber树称为 workInProgress Fiber树

current Fiber树中的 Fiber节点被称为 current fiberworkInProgress Fiber树中的 Fiber节点被称为 workInProgress fiber,他们通过 alternate 属性连接。

1
2
currentFiber.alternate === workInProgressFiber;
workInProgressFiber.alternate === currentFiber;

React应用的根节点通过使 current 指针在不同 Fiber树rootFiber 间切换来完成 current Fiber 树指向的切换。

即当 workInProgress Fiber树 构建完成交给 Renderer 渲染在页面上后,应用根节点的 current 指针指向 workInProgress Fiber树 ,此时 workInProgress Fiber树就变为 current Fiber树

每次状态更新都会产生新的 workInProgress Fiber树,通过 currentworkInProgress 的替换,完成 DOM 更新。

接下来我们以具体例子讲解 mount时update时的构建 / 替换流程。

mount 时

考虑如下例子:

1
2
3
4
5
6
7
function App() {
return (
<h1>hello<span style={{ color: 'red' }}>world</span></h1>
)
}

ReactDOM.render(<App/>, document.getElementById('root'));
  1. 首次执行 ReactDOM.render 会创建 fiberRootNode(源码中叫 fiberRoot)和 rootFiber。其中 fiberRootNode 是整个应用的根节点,rootFiber<App/> 所在组件树的根节点。

之所以要区分 fiberRootNoderootFiber,是因为在应用中我们可以多次调用 ReactDOM.render 渲染不同的组件树,他们会拥有不同的 rootFiber。但是整个应用的根节点只有一个,那就是 fiberRootNode

fiberRootNodecurrent 会指向当前页面上已渲染内容对应 Fiber树,即 current Fiber树

fiberRootNode

fiberRootNode.current = rootFiber;

由于是首屏渲染,页面中还没有挂载任何 DOM,所以 fiberRootNode.current 指向的 rootFiber 没有任何子Fiber节点(即 current Fiber树为空)。

  1. 接下来进入 render阶段,根据组件返回的 JSX 在内存中依次创建 Fiber节点并连接在一起构建 Fiber树,被称为 workInProgress Fiber树。(下图中右侧为内存中构建的树,左侧为页面显示的树)

在构建 workInProgress Fiber树时会尝试复用 current Fiber树中已有的 Fiber节点内的属性,在首屏渲染时只有 rootFiber 存在对应的 current fiber(即 rootFiber.alternate)。

  1. 图中右侧已构建完的 workInProgress Fiber树commit阶段渲染到页面。

此时 DOM 更新为右侧树对应的样子。fiberRootNodecurrent 指针指向 workInProgress Fiber树使其变为 current Fiber 树

update 时

  1. 接下来我们点击 p节点触发状态改变,这会开启一次新的 render阶段并构建一棵新的 workInProgress Fiber 树

mount 时一样,workInProgress fiber 的创建可以复用 current Fiber树对应的节点数据。

  1. workInProgress Fiber 树render阶段完成构建后进入 commit阶段渲染到页面上。渲染完毕后,workInProgress Fiber 树变为 current Fiber 树

渲染过程