狗教我React——原理篇之React整体架构解读

前言

了解React的多少都见过这句话:React16之后,改用了Fiber 架构。那么,到底什么是Fiber架构?之前的架构是什么?为什么要使用Fiber架构代替之前的呢?

其实关于Fiber架构的解读可深可浅,然而我曾经对Fiber架构的认知是👇

emmm这个确实过于浅了。

此篇文章作为我的学习记录,将概括性地总结讲述Fiber架构的关键概念。具体的深入内容将会在之后的文章中介绍。

  • 本文前置知识:Virtual DOM

正文

栈式架构(Stack Reconcilation)

在React Fiber架构之前,React使用的是栈式架构(Stack Reconcilation) ,它基于递归的方式来进行 Virtual DOM 的比较和更新。

尽管 Stack Reconciler 在初期推动了 React 的发展,但随着 Web 应用程序的复杂性增加和用户需求的提升,它的同步执行特性在处理大型应用或复杂交互时表现出了一些局限性。

js 复制代码
{
  type : "div",
  props : {
    id : "list",
    children : [
      {
        type : "ul",
        props : {
          children : [{
            type : "li",
            props : {
              children : "apple"
            }
          },//...
          }]
        }
      }
    ]
  }
}

Stack架构在进行两棵虚拟DOM树对比的时候,递归遍历上面的结构。这种同步执行的特性意味着一旦开始更新操作,需要一直执行完所有比较和更新,无法中断或分段处理。

虽然虚拟 DOM 是 JS 层面的计算,比起真实的DOM操作已经有了很大的优化,但是在应用程序中有大量的组件和复杂的数据结构时,递归的比较和更新依然会消耗大量的计算资源和时间,导致页面在更新过程中出现卡顿现象,直接影响到用户的交互体验。

另一方面, Stack Reconciler 没有引入任务优先级的概念,所有更新任务都按照生成的顺序依次同步执行。这意味着如果一个高优先级的更新任务需要立即响应,但此时正在进行的低优先级更新任务还未完成,就会造成用户体验的延迟和不流畅。

(举个例子:用户在输入时,不到1s的延迟就会觉得很卡;在loading时,几秒等待也能接受。所以前者高优先级,后者低优先级)

简单总结一下,Stack Reconciler性能限制主要分为两类:

  1. CPU瓶颈:即应用的计算需求超过了CPU的处理能力。这里的CPU 瓶颈通常指的是由于大量的 Virtual DOM 操作、组件更新或复杂的计算任务导致的 CPU 资源消耗过高,主线程(负责UI渲染的线程)被长时间占用,从而影响应用的响应速度和用户体验。

  2. I/O瓶颈 :I/O瓶颈主要与网络延迟有关,是客观存在的。前端只能尽量减少其对用户的影响,例如区分不同操作的优先级

Fiber架构的关键概念

1. Fiber节点

Fiber 节点是 Fiber 架构的核心概念之一,它是一种虚拟DOM的实现方式。

Fiber本质上是一个对象, 使用了链表结构。和之前的递归树实现 Virtual DOM不同的是,对象之间使用链表的结构串联。一个 fiber包括了 child(第一个子节点)、sibling(同级节点)、return(上一级节点)等属性。

如上图,fiber的child 指向下一级元素,sibling 指向同级元素,return 指向上一级元素。

这种结构和递归树相比,最重要的优势是在进行虚拟树的对比计算时,过程可以中断和恢复。

源码中的Fiber 对象(已简化处理):

js 复制代码
function FiberNode(
  tag: WorkTag, // 标记节点类型,例如 FunctionComponent、ClassComponent、HostRoot 等
  pendingProps: mixed, // 待处理的props
  key: null | string, // 节点的key
  mode: TypeOfMode, // 渲染模式,例如是否在严格模式下或是否是异步更新
) {
  // 实例属性
  this.tag = tag;
  this.key = key;
  this.elementType = null; // 组件的元素类型,可能为定义改组件的函数或类、DOM元素类型等
  this.type = null; // 实际的 JavaScript 对象类型(如函数、类、原生 DOM 节点等)
  this.stateNode = null; // 节点对应的实例或 DOM 节点

  // Fiber树结构
  this.return = null; // 上一级节点
  this.child = null; // 第一个子节点
  this.sibling = null; // 下一个同级节点
  this.index = 0; // 在上一级节点中的索引

  this.ref = null;
  
  // Props和State
  this.pendingProps = pendingProps;
  this.memoizedProps = null;
  this.updateQueue = null;
  this.memoizedState = null;
  this.dependencies = null;

  this.mode = mode;

  // Effects
  this.flags = NoFlags;
  this.subtreeFlags = NoFlags;
  this.deletions = null;

  this.lanes = NoLanes;
  this.childLanes = NoLanes;

  this.alternate = null;

  if (enableProfilerTimer) {
   // 以下是性能相关的属性,在开发模式下使用
   // ...
  }
  // 开发模式下的调试相关属性
  if (__DEV__) {
    //...
  }
}

2. 调度器Scheduler

React16之后,新增了调度器Scheduler组件,负责管理和调度任务执行

前面提到,用户对于不同操作的感知不同,如果在网络延迟客观存在的情况下不对各种操作的优先级区分,细微的延迟就会造成用户体验的不流畅。

而Scheduler就是解决这个问题的。React定义了不同的优先级级别,如 Immediate(最高优先级,用于处理用户交互)、Normal(默认优先级,一般的更新任务)、Low(低优先级,如后台任务)等。调度器可以根据任务的优先级来安排它们的执行顺序,以尽快地响应用户的操作,提升用户体验。

3. 时间切片 TimeSlice

Fiber架构引入时间切片(Time Slicing) 的概念,即将大的渲染任务分解为多个较小的片段,每个片段都可以在一帧内完成,这样可以防止长时间的任务阻塞主线程,保持界面的流畅性。

时间切片允许React在每个片段之间执行其他优先级更高的任务,从而在不同任务之间找到一个平衡点,提高整体的响应性和用户体验。

4. 双重缓冲Double Buffering

双重缓冲是一种渲染优化技术,其使用两个Fiber树 来管理渲染,即当前树 current tree工作树 work-in-progress tree。当前树代表屏幕上当前显示的内容,而工作树用于准备下一次的渲染更新,用以实现平滑的更新。

相关推荐
fruge15 小时前
前端正则表达式实战合集:表单验证与字符串处理高频场景
前端·正则表达式
baozj15 小时前
🚀 手动改 500 个文件?不存在的!我用 AST 撸了个 Vue 国际化神器
前端·javascript·vue.js
用户40993225021215 小时前
为什么Vue 3的计算属性能解决模板臃肿、性能优化和双向同步三大痛点?
前端·ai编程·trae
海云前端115 小时前
Vue首屏加速秘籍 组件按需加载真能省一半时间
前端
蛋仔聊测试15 小时前
Playwright 中route 方法模拟测试数据(Mocking)详解
前端·python·测试
零号机15 小时前
使用TRAE 30分钟极速开发一款划词中英互译浏览器插件
前端·人工智能
molly cheung15 小时前
FetchAPI 请求流式数据 基本用法
javascript·fetch·请求取消·流式·流式数据·流式请求取消
疯狂踩坑人15 小时前
结合400行mini-react代码,图文解说React原理
前端·react.js·面试
Mintopia15 小时前
🚀 共绩算力:3分钟拥有自己的文生图AI服务-容器化部署 StableDiffusion1.5-WebUI 应用
前端·人工智能·aigc
街尾杂货店&15 小时前
CSS - transition 过渡属性及使用方法(示例代码)
前端·css