我们已经确定 Fiber 的主要目标是使 React 能够利用调度。具体来说,我们需要能够
- 暂停工作,稍后再回来。
- 为不同类型的工作分配优先级。
- 重用之前完成的工作。
- 如果不再需要,则中止工作。
为了做到这一点,我们首先需要一种将工作分解为单元的方法。从某种意义上说,这就是纤维。一根纤维代表一个工作单元。
更进一步,让我们回到React 组件作为数据函数的概念,通常表示为
v = f(d)
因此,渲染一个 React 应用程序类似于调用一个函数,该函数的主体包含对其他函数的调用,依此类推。这个类比在考虑纤维时很有用。
计算机通常跟踪程序执行的方式是使用调用堆栈。当一个函数被执行时,一个新的栈帧被添加到栈中。该堆栈帧表示该函数执行的工作。
在处理 UI 时,问题是如果一次执行过多的工作,可能会导致动画掉帧并且看起来不连贯。更重要的是,如果这些工作被更新的更新所取代,其中一些工作可能是不必要的。这是 UI 组件和函数之间的比较失败的地方,因为组件比一般的函数具有更具体的关注点。
较新的浏览器(和 React Native)实现了有助于解决这个确切问题的 API:requestIdleCallback安排在空闲期间调用低优先级函数,并requestAnimationFrame安排在下一个动画帧调用高优先级函数。问题是,为了使用这些 API,您需要一种将渲染工作分解为增量单元的方法。如果你只依赖调用堆栈,它会一直工作直到堆栈为空。
如果我们可以自定义调用堆栈的行为以优化渲染 UI,那不是很好吗?如果我们可以随意中断调用堆栈并手动操作堆栈帧,那不是很好吗?
这就是 React Fiber 的目的。Fiber 是堆栈的重新实现,专门用于 React 组件。您可以将单根前卫视为一个虚拟堆栈帧。
重新实现堆栈的优点是您可以将堆栈帧保留在内存中,并根据需要(以及何时)执行它们。这对于实现我们的调度目标至关重要。
除了调度之外,手动处理堆栈帧释放了并发和错误边界等功能的潜力。
Stack reconciler
“stack” reconciler 是 React 15 及更早的解决方案
Fiber reconciler
“fiber” reconciler 是一个新尝试,致力于解决 stack reconciler 中固有的问题,同时解决一些历史遗留问题。Fiber 从 React 16 开始变成了默认的 reconciler。
它的主要目标是:
- 能够把可中断的任务切片处理。
- 能够调整优先级,重置并复用任务。
- 能够在父元素与子元素之间交错处理,以支持 React 中的布局。
- 能够在 render() 中返回多个元素。
- 更好地支持错误边界。
你可以在这里和这里,深入了解 React Fiber 架构。虽然这已经在 React 16 中启用了,但是 async 特性还没有默认开启。
源代码在 packages/react-reconciler 目录下。