当前位置: 首页 > 工具软件 > fiber > 使用案例 >

对fiber的一点了解

唐恺
2023-12-01

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。
    
  • pendingPropsmemoizedProps

    //从概念上讲,props 是函数的参数。fiber`pendingProps`在执行开始时`memoizedProps`设置,并在执行结束时设置。
    
    //当传入`pendingProps`等于 时`memoizedProps`,表示可以重复使用fiber先前的输出,从而防止不必要的工作。
    
  • pendingWorkPriority

    一个数字,表示纤程所代表的工作的优先级。除NoWork0 外,数字越大表示优先级越低。例如,您可以使用以下函数来检查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创建。然后将输出沿树向上传输。
    
    输出是最终提供给渲染器的内容,以便它可以将更改刷新到渲染环境。定义如何创建和更新输出是渲染器的责任。
    

淘系前端文章

掘金文章

掘金文章

 类似资料: