Skip to content

Latest commit

 

History

History
100 lines (62 loc) · 7.31 KB

2017-09-08-[译]-react-fiber-architecture.md

File metadata and controls

100 lines (62 loc) · 7.31 KB
Error in user YAML: (<unknown>): did not find expected key while parsing a block mapping at line 1 column 1
---
title: [译]react-fiber-architecture
date: 2017-09-08
status: finished
---

原文:https://github.com/acdlite/react-fiber-architecture

React Fiber的目标是增加其对动画,布局和手势等领域的适用性。其首要特征是渐进渲染:将渲染工作分解成块并将其分散在多个帧上的能力。

其他主要功能包括:在新的更新进入时具有暂停,中止或重用工作的能力;为不同类型的更新分配优先级的能力;新的并发函数。

概念

调和器:reconciliation

reconciliation :React使用的算法将一个树与另一个树进行比较,以确定哪些部分需要更改 update:改变用于渲染react应用的数据。通常是setState的结果。最终导致重新渲染。

React的API的核心思想更多的考虑更新会导致整个应用进行更新。允许开发人员声明性地引用,而不是担心如何有效地将应用程序从任何特定状态转换到另一个状态。

React具有优化功能,可以在保持良好的性能的同时创建整个应用程序重新呈现的外观。这些优化的大部分是称为协调的过程的一部分。

调和器是普遍被理解为“虚拟DOM”的算法。通用的一个思路是:渲染React应用程序时,会生成描述该应用程序的节点树,并将其保存在内存中。然后将该树刷新到渲染环境。比如说:在浏览器应用程序的情况下,它被转换为一组DOM操作。当应用程序更新(通常通过setState)时,会生成一个新的树。新树与上一个树分开,以计算需要哪些操作来更新渲染的应用程序。

虽然Fiber是调和器的基础上重写,但React文档中描述的高级算法将大体相同。要点是:

  • 假设不同的组件类型生成大量不同的树。react不会尝试去区分它们,而是完全取代旧树。
  • 通过key对列表的进行区分。key应该是“稳定,可预测和唯一”

调和器和渲染

DOM只是React可以进行渲染的渲染环境之一,它还可以通过React Native进行原生iOS和Android的视图渲染。 (这就是为什么叫做“虚拟DOM”有点不正确。)

react 可以支持这么多的渲染环境的主要原因是调和器和渲染器是分开的。调和器负责计算树的哪些部分已经改变的;然后,渲染器会使用该信息来实际更新渲染的应用程序。

分离意味着React DOM和React Native可以使用它们自己的渲染器,同时共享由React核心提供的相同的协调器。

fiber对调和器进行了修复。它不主要关注渲染,尽管渲染器将需要更改以支持(并利用)新的架构。

Scheduling 调度

scheduling : 确定何时进行工作的过程
work: 任何必须执行的计算。work通常是更新的结果(例如setState)。

在其当前实现中,React递归地遍历树,并在单次tick(周期)时调用整个更新的树的渲染函数。然而,将来它可能会延迟一些更新以避免丢帧。

这是React设计中的一个常见主题。一些流行的库实现了“push”方式,当有新数据时执行计算。但是react坚持“pull”的方式,能够让计算可以延迟,直到必要的时候再进行计算。

React不是一个通用的数据处理库。它是构建用户界面的库。我们认为它在应用程序中是独一无二的,以了解现在哪些计算是相关的,哪些是不相关的。

如果某些东西在屏幕外,我们可以延迟与之相关的任何逻辑。如果数据的速度比帧率快,我们可以合并和批量更新。

我们可以通过不太重要的后台工作(例如渲染从网络加载的新内容)来优化,来自用户交互(例如由按钮点击引起的动画)的工作,以避免丢帧。

主要有以下几个点:

  • 在UI中,每次更新都不需要立即应用;事实上,这样做可能是浪费的,导致帧丢失和降级用户体验。
  • 不同类型的更新具有不同的优先级 - 动画更新需要比数据存储的更新更快地完成。
  • 基于推送的方法要求应用程序(您,程序员)决定如何安排工作。基于拉式的方法允许框架(React)变得聪明,并为您做出决定。

React目前并没有很充分地利用调度;更新会导致整个子树被立即重新呈现。利用调度技术重新修改React的核心算法,是Fiber的驱动思想。

fiber

我们已经确定,Fiber的主要目标是使React充分能够利用调度。具体来说,我们需要能够做到以下几点:

  • 能暂停工作并随后恢复
  • 为不同类型的工作分配优先级
  • 重用以前完成的工作
  • 如果不再需要,中止工作。

为了做到这一点,我们首先需要一种将工作分解为单位的方法。在某种意义上,这就是fiber。fiber代表工作单位。

v = f(d)

因此,渲染React应用程序类似于调用一个函数,这个函数的主体包含对其他函数的调用,等等。这种比喻在如何开发fiber时很有用。

计算机通常跟踪程序的执行方式是使用执行栈(call stack)。执行功能时,将新的堆栈帧添加到堆栈中。该堆栈帧表示该功能执行的工作。

在处理UI时,问题是如果一次性执行的工作太多,它可能会导致动画丢帧,看起来很乱。而且,如果更新版本被替代,那么这些工作可能是不必要的。这就是是UI组件和普通功能函数之间的比较最大的痛点,因为组件比普通的函数相比要处理一些更具体的问题。

现代浏览器(和React Native)提供了有助于解决这个问题的API:requestIdleCallback可以在空闲时间进行调度,调用的低优先级功能,requestAnimationFrame调度在下一个动画帧上调用的高优先级功能。但问题是,为了使用这些API,您需要一种将渲染工作分解为增量单位的方法。如果您只依赖于运行栈,那它会等到堆栈为空时候才会继续工作。

如果我们可以自定义调用堆栈的行为来优化渲染UI,那不是很好吗?如果我们可以随意中断调用堆栈并手动操作堆栈帧,那不是很好吗?

这就是React Fiber的目的。Fiber是专门基于React组件重新实现堆叠。您可以将单个Fiber视为虚拟堆叠帧(virtual stack frame)。

重新实现堆栈的优点是您可以将堆栈框架保留在内存中,然后执行(或只要你想,随时可以执行)。这对于完成我们安排的目标至关重要。

除了调度之外,手动处理堆栈帧会释放诸如并发和错误边界等功能的潜力。我们将在以后的章节中介绍这些主题

fiber架构

具体来说,fiber是一个JavaScript对象,其中包含有关组件,输入及其输出的信息。

fiber对应于堆叠帧,但它也对应于组件的实例

type and key

fiber的type和key与React元素的用途相同。 (实际上,当从元素中创建fiber时,这两个字段直接被复制。)

fiber的type描述了它对应的组件。对于复合组件,type是函数或类组件本身。对于主机组件(div,span等),type是一个字符串。

在概念上,type是由堆栈帧跟踪其执行的函数(如在v = f(d)中)。

与type一起,在调和期间使用key来确定fiber是否可以重复使用。

child and sibling

这些字段指向其他fiber,描述fiber的递归树结构。