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 应用程序的复杂性增加和用户需求的提升,它的同步执行特性在处理大型应用或复杂交互时表现出了一些局限性。

{
  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 对象(已简化处理):

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。当前树代表屏幕上当前显示的内容,而工作树用于准备下一次的渲染更新,用以实现平滑的更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值