title: 对fiber的了解
order: 1
看了一篇官网推荐的Github文章,一篇淘系前端文章,快速看了掘金两篇大佬文章,写下这篇总结
Fiber 是 React 16 中新的
协调引擎
。它的主要目的是使 Virtual DOM 可以进行增量式渲染。了解更多.Fiber reconciler
“fiber” reconciler(调节器,用来diff的) 是一个新尝试,致力于解决 stack reconciler 中固有的问题,同时解决一些历史遗留问题。Fiber 从 React 16 开始变成了默认的 reconciler。
它的主要目标是:
- 能够把可中断的任务切片处理。
- 能够调整优先级,重置并复用任务。
- 能够在父元素与子元素之间交错处理,以支持 React 中的布局。
- 能够在
render()
中返回多个元素。- 更好地支持错误边界。
你可以在这里和这里,深入了解 React Fiber 架构。虽然这已经在 React 16 中启用了,但是 async 特性还没有默认开启。
前言
React的更新关键点:
- 不同组件类型会生成完全不同的树,React不会区分它们,而会完全替换旧树
- diff算法受限与keys,keys是唯一的,稳定的可预测的
React是协调器和渲染器分离的,协调器负责计算树的哪些部分发生了变化;然后渲染器使用该信息来实际更新渲染的应用程序。这种分离意味着 React DOM 和 React Native 可以使用自己的渲染器,同时共享由 React 核心提供的相同的协调器。Fiber 重新实现了协调器。它主要不涉及渲染,尽管渲染器需要更改以支持(并利用)新架构。
如果有东西在屏幕外,我们可以延迟与之相关的任何逻辑。如果数据到达速度快于帧速率,我们可以合并和批量更新。我们可以将来自用户交互的工作(例如由按钮点击引起的动画)优先于不太重要的后台工作(例如渲染刚从网络加载的新内容),以避免丢帧。
关键点是:
- 在 UI 中,没有必要立即应用每个更新;事实上,这样做可能会造成浪费,导致丢帧并降低用户体验。
- 不同类型的更新有不同的优先级——动画更新需要比数据存储更新更快地完成。
- 基于推送的方法要求应用程序(您,程序员)决定如何安排工作。基于拉取的方法允许框架 (React) 变得智能并为您做出这些决定。
- React 目前并没有以重要的方式利用调度;更新会立即重新渲染整个子树。彻底改造 React 的核心算法以利用调度的优势是 Fiber 背后的驱动思想。
一.什么是调度(scheduling),什么是work?
scheduling:确定何时应该执行工作的过程。所以就是 何时执行更新的结果过程。
work:必须执行的任何计算。工作通常是更新的结果(例如setState
)。
二.介绍
React Fiber 的目标是提高其对动画、布局( animation, layout, and gestures)等领域的适用性。它的主要功能是增量渲染:能够将渲染工作分成块并将其分散到多个帧上。
三.Fiber设计思想
Fiber 是对 React 核心算法的重构,facebook 团队使用两年多的时间去重构 React 的核心算法,在React16 以上的版本中引入了 Fiber 架构,其中的设计思想是非常值得我们学习的。
我们已经确定 Fiber 的主要目标是使 React 能够利用调度。具体来说,我们需要能够
- 暂停工作,稍后再回来。
- 为不同类型的工作分配优先级。
- 重用以前完成的工作。
- 如果不再需要,则中止工作。
为了做到这一点,我们首先需要一种将工作分解成单元的方法,从某种意义上说,一个fiber就是一个工作单元
较新的浏览器(和 React Native)实现的 API 有助于解决这个确切的问题:requestIdleCallback
安排一个低优先级的函数在空闲期间调用,并requestAnimationFrame
安排一个高优先级的函数在下一个动画帧上调用。问题是,为了使用这些 API,您需要一种将渲染工作分解为增量单元的方法
。如果你只依赖调用栈,它会一直工作直到栈为空。
如果我们可以自定义调用堆栈的行为来优化渲染 UI,那不是很好吗?如果我们可以随意中断调用堆栈并手动操作堆栈帧,那不是很好吗?
这就是 React Fiber 的目的。Fiber 是堆栈的重新实现,专门用于 React 组件。
重新实现堆栈的优点是您可以将堆栈帧保存在内存中
,并根据需要(以及任何时候)执行它们。这对于实现我们的调度目标至关重要。
具体来说,fiber是一个 JavaScript 对象,其中包含有关组件、其输入和输出的信息。
一个fiber对应一个栈帧,但也对应一个组件的实例。
未来部分:
- 调度程序如何找到下一个要执行的工作单元。
- 如何通过光纤树跟踪和传播优先级。
- 调度程序如何知道何时暂停和恢复工作。
- 工作如何刷新并标记为完成。
- 副作用(例如生命周期方法)如何工作。
- 什么是协程以及如何使用它来实现上下文和布局等功能。
四.fiber的一些属性
-
type和key
type对于复合组件,类型是函数或类组件本身。对于宿主组件(div、span等),类型是字符串。 key决定是否复用
-
child和sibling
//这些字段指向其他fiber,描述fiber的递归树结构。 //子fiber对应于组件render方法返回的值 function Parent() { return <Child /> } //兄弟字段解释了render返回多个子项的情况(Fiber 中的一个新功能!): function Parent() { return [<Child1 />, <Child2 />] } //子fiber形成一个单向链表,其头部是第一个子fiber。因此,在这个例子中,Child1是Parent的孩子,Child1的兄弟是Child2。
-
return
//return是程序在处理当前fiber后应返回的fiber。它在概念上与堆栈帧的返回地址相同。它也可以被认为是父fiber。 //如果一个fiber有多个子fiber,则每个子fiber的返回fiber都是父fiber。所以在上一节的例子中,Child1返回fiberChild2是Parent。
-
pendingProps
和memoizedProps
//从概念上讲,props 是函数的参数。fiber`pendingProps`在执行开始时`memoizedProps`设置,并在执行结束时设置。 //当传入`pendingProps`等于 时`memoizedProps`,表示可以重复使用fiber先前的输出,从而防止不必要的工作。
-
pendingWorkPriority
一个数字,表示纤程所代表的工作的优先级。除
NoWork
0 外,数字越大表示优先级越低。例如,您可以使用以下函数来检查fiber的优先级是否至少与给定级别一样高:function matchesPriority(fiber, priority) { return fiber.pendingWorkPriority !== 0 && fiber.pendingWorkPriority <= priority }
调度程序使用优先级字段来搜索下一个要执行的工作单元。
-
alternate
(交替,轮流)//flush 刷新fiber就是将其输出渲染到屏幕上 //work-in-progress 尚未完成的fiber;从概念上讲,尚未返回的堆栈帧。 //在任何时候,一个组件实例最多有两个与之对应的fiber:当前的、已刷新的纤程和正在进行中的纤程。 //A fiber's alternate is created lazily using a function called cloneFiber。与其总是创建一个新对象,不如cloneFiber尝试重用fiber的备用对象(如果存在),从而最大限度地减少分配。
-
output
//host component 宿主组件 React 应用程序的叶节点。它们特定于渲染环境(例如,在浏览器应用程序中,它们是`div`、`span` 等)。在 JSX 中,它们使用lowercase tag。 从概念上讲,fiber的输出是函数的返回值。 每个fiber最终都有输出,但输出仅在叶节点由host components创建。然后将输出沿树向上传输。 输出是最终提供给渲染器的内容,以便它可以将更改刷新到渲染环境。定义如何创建和更新输出是渲染器的责任。