React 核心原理与Fiber架构

目录

一、虚拟 DOM

二、Diffing 算法

三、Fiber 架构

四、渲染流程

1. Render 阶段(可中断异步过程)

2. Commit 阶段(同步不可中断)

五、时间切片(Time Slicing)

六、核心流程步骤总结

1. 状态更新触发

2. Render 阶段(异步可中断,构建 Fiber 树)

3. Commit 阶段(同步不可中断,更新真实 DOM)

4. 双缓存机制切换

5. 调度系统核心支撑

七、组件触发渲染的时机


相关内容: 

React Fiber 架构原理:关于 Fiber 树的一切

React核心原理浅析

二十分钟掌握React核心理念,老鸟快速入门指南


一、虚拟 DOM

React 使用虚拟 DOM 来表示 UI 的状态。虚拟 DOM 是一个轻量级的 JavaScript 对象,每个节点包含 tag(标签名)、props(属性)、children(子节点)。

核心价值在于性能优化 —— 直接操作真实 DOM 会触发浏览器重排 / 重绘,成本很高;而虚拟 DOM 先在内存中通过 Diff 算法比对状态变更,再批量更新真实 DOM,减少浏览器操作次数。

二、Diffing 算法

Diffing 算法用于比较新旧虚拟 DOM 树,以最小的操作次数将旧 DOM 树转换为新 DOM 树。

React 提出了复杂度为 O(n) 的启发式算法,通过设置 key 属性来标识一组同级子元素,从而高效地更新真实 DOM。

  1. 同层比较(Tree Diff):仅逐层对比节点,不跨层级遍历。若节点类型不同,直接销毁整棵子树及其组件实例并重建。
  2. Key 值优化:列表渲染时需为元素提供唯一 key,用于标识节点身份。通过 key,React 可识别节点的移动或复用,避免全量更新。
  3. 组件类型比对:若组件类型相同,则递归更新子节点;若类型不同,则卸载旧组件并挂载新组件。

不指定 key 的后果:

React 通过 ​​key + 组件类型​​ 的组合来识别元素的身份,没有 key 时默认使用 ​​数组索引​​ 作为 key。

若用索引作为 key,当列表项顺序变化或中间插入 / 删除元素时,React 会错误地认为大量节点需重新创建,而非移动或更新,导致不必要的 DOM 操作(如重复卸载 / 挂载组件),严重影响性能。

索引作为 key 的问题本质:

  • ​绑定问题​​:使用索引作为 key 时状态绑定到​位置​,而非​数据​​
  • DOM复用规则​​:React 只复用相同 key 对应的 DOM 节点
  • ​数据与DOM分离​​:React 更新内容但不更新状态
  • ​状态漂移​​:输入状态留在原位置,被新元素继承

使用唯一 ID 作为 key 可以解决这个问题,因为它确保状态与数据项(而非位置)保持一致关联。


三、Fiber 架构

Fiber 架构解决了传统同步渲染阻塞主线程的问题,实现可中断的异步渲染,支持时间切片和优先级调度。

Fiber 节点结构

每个组件对应一个 Fiber 节点,构成链表树(非传统递归树)。节点包含组件类型、状态、副作用标记(effectTag,如删除、新增节点)、节点指针:child(指向第一个子节点)、sibling(指向下一个兄弟节点)、return(指向父节点)。

双缓存机制

  • Current Tree:当前已渲染到页面的 Fiber 树。
  • WorkInProgress Tree:后台构建的新 Fiber 树,用于计算变更。

两棵树通过 alternate 指针关联,每次更新时新建 WorkInProgress Tree,构建完成后直接替换Current Tree,保证视图连续性。


四、渲染流程

1. Render 阶段(可中断异步过程)

构建 Fiber 链表树,通过 Diff 标记副作用(如节点增删)。

1. 深度优先遍历
从根节点开始,采用深度优先遍历,通过 beginWork 向下处理每个 Fiber 节点,逐步构建 Fiber 链表树。

2. Diffing 算法执行
对比新旧子节点,决定复用/移动/删除,并标记 effectTag(如 Placement 移动节点)。

  • 节点复用条件:父节点已复用,且 key 和 type 相同。
  • 子节点 Diff 顺序:先尝试单节点匹配,再处理多节点末尾增删(一轮循环),最后处理复杂移动场景(二轮循环),尽可能减少节点移动开销。

3. 向上回溯
当节点无子节点时,进入 completeUnitOfWork,自底向上收集 effectTag,将子节点的 effectList 合并到父节点,最终形成从根节点到叶节点的副作用链表。

4. 中断与恢复
利用时间切片(Time Slicing)将任务拆分为微任务,在浏览器空闲时执行,避免阻塞主线程。每处理完一个节点,检查剩余时间片,时间耗尽时暂停,通过全局变量保存进度,浏览器空闲时通过调度器恢复任务。

2. Commit 阶段(同步不可中断)

批量执行副作用,更新真实 DOM。此阶段必须一气呵成,确保 DOM 操作的原子性。

遍历 effectList,批量更新真实 DOM(执行 effectTag 对应的操作,如创建、删除节点)。触发回调,处理 ref 和 useEffect。


五、时间切片(Time Slicing)

时间切片策略将渲染任务拆分为微任务单元,利用浏览器空闲时段执行,提升响应性。

调度器:模拟 requestIdleCallback 功能(兼容旧浏览器),设置任务优先级,通过 MessageChannel 实现异步调度,将任务拆分为小单元,每次执行完一个单元后,检查是否有高优先级任务插队,若有则暂停当前任务。

任务优先级:分为五级(紧急交互 > 过渡动画 > 普通更新 > 延迟更新 > 过期任务),高优先级任务可插队执行,中断低优先级任务;低优先级任务可暂停或丢弃,避免占用主线程。例如,用户点击按钮时,渲染任务会被暂停,优先处理点击回调。

调度系统通过四层架构实现:

  1. SchedulerHostConfig:对接浏览器底层能力,利用 MessageChannel 计算空闲时间,提供空闲回调机制,是 Fiber 调度的基础。
  2. Scheduler:核心任务管理模块,定义五级优先级,通过双向循环链表维护任务池,实现任务的注册、取消和优先级排序,并在浏览器空闲时执行任务。
  3. SchedulerWithReactIntegration:抹平调度接口,将 Scheduler 与 React 的更新流程整合,例如在状态更新时触发调度。
  4. ReactFiberScheduler:应用层调度入口,将 React 的更新任务(如 Fiber 树的构建)包装为 Scheduler 可处理的任务,在 Render 阶段通过 shouldYield() 检查是否需要中断任务,确保主线程不阻塞。

六、核心流程步骤总结

1. 状态更新触发

  • 因用户交互(如点击)、setState 或 Hooks 更新函数调用,触发组件状态变更,生成新虚拟 DOM,启动更新流程。

2. Render 阶段(异步可中断,构建 Fiber 树)

  • 任务拆分与优先级调度:利用 时间切片 将渲染任务拆分为微任务,通过调度器按优先级异步执行,可被高优先级任务中断。
  • Fiber 树构建与 Diff 执行
    • 深度优先遍历,通过 beginWork 对比新旧虚拟 DOM,复用 key 和类型相同的节点,标记新增 / 更新 / 删除的 副作用(effectTag)
    • 子节点 Diff 按 “单节点匹配 → 末尾增删 → 复杂移动” 顺序优化,减少 DOM 操作。
  • 副作用收集:通过 completeUnitOfWork 自底向上合并副作用,形成根节点的 effectList 链表
  • 中断与恢复:每处理完一个 Fiber 节点,检查时间片是否耗尽,耗尽时暂停任务并保存进度,浏览器空闲时恢复。

3. Commit 阶段(同步不可中断,更新真实 DOM)

  • 遍历 effectList,批量执行 DOM 操作(创建、删除、更新节点),确保操作原子性。
  • 触发生命周期回调(如 useEffectref 更新),完成视图渲染。

4. 双缓存机制切换

  • 构建完成的 WorkInProgress Tree 替换为 Current Tree,通过 alternate 指针复用节点数据,保证视图连续性。

5. 调度系统核心支撑

  • 通过 四层架构(SchedulerHostConfig、Scheduler、SchedulerWithReactIntegration、ReactFiberScheduler)实现任务优先级管理、时间切片和异步调度,避免主线程阻塞。

七、组件触发渲染的时机

  • 状态(state)更新:调用更新函数导致组件状态变化。
  • props 变化:父组件传递的 props 值或引用发生改变。
  • 上下文(Context)变化:组件依赖的 Context 值更新。
  • 父组件渲染:父组件重新渲染触发子组件默认更新(未优化时)。
  • 强制更新:调用forceUpdate()跳过常规更新判断。
  • 组件 key 变化:触发旧组件卸载和新组件挂载(相当于重新渲染)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/87981.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/87981.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【破局痛点,赋能未来】领码 SPARK:铸就企业业务永续进化的智慧引擎—— 深度剖析持续演进之道,引领数字化新范式

摘要 在瞬息万变的数字时代,企业对业务连续性、敏捷创新及高效运营的需求日益迫切。领码 SPARK 融合平台,秉持“持续演进”这一核心理念,以 iPaaS 与 aPaaS 为双擎驱动,深度融合元数据驱动、智能端口调度、自动化灰度切换、AI 智…

掌握C++核心特性

目标: 掌握C核心特性,为嵌入式开发打基础 好的,我来为你详细梳理一下 继承与多态、虚函数 相关的知识点,包括单继承、多继承、虚函数表机制、纯虚函数与抽象类、动态绑定。以下内容适合中等难度层次的理解,便于考试复…

python的高校教师资源管理系统

目录 技术栈介绍具体实现截图系统设计研究方法:设计步骤设计流程核心代码部分展示研究方法详细视频演示试验方案论文大纲源码获取/详细视频演示 技术栈介绍 Django-SpringBoot-php-Node.js-flask 本课题的研究方法和研究步骤基本合理,难度适中&#xf…

Java Collections工具类:高效集合操作

Collections工具类概述 Collections是Java提供的集合操作工具类&#xff0c;位于java.util包中&#xff0c;包含大量静态方法&#xff0c;用于对List、Set、Map等集合进行排序、查找、替换、同步化等操作。 常用方法及代码示例 排序操作 sort(List<T> list)&#xff1a…

vue指令总结

vue指令总结 一、总述 二、代码实现&#xff08;内含大量注释&#xff09; <!DOCTYPE html> <html> <head><meta charset"utf-8"><title>vue入门</title><!-- 使用Vue 3官方CDN --><script src"https://unpkg.c…

RUP——统一软件开发过程

RUP概述 RUP&#xff08;Rational Unified Process&#xff09;&#xff0c;统一软件开发过程&#xff0c;统一软件过程是一个面向对象且基于网络的程序开发方法论。 在RUP中采用“41”视图模型来描述软件系统的体系结构。“41”视图包括逻辑视图、实现视图、进程视图、部署视…

SpringBoot电脑商城项目--增加减少购物车商品数量

1. 持久层 1.1 规划sql语句 执行更新t_cart表记录的num值根据cid查询购物车的数据是否存在 select * from t_cart where cid#{cid} 1.2 接口和抽象方法 /*** 获取购物车中商品的数据总数* return 购物车中商品的数据总数*/Cart findByCid(Integer cid); 1.3 xml文件中sql映射…

零基础学习Redis(13) -- Java使用Redis命令

上期我们学习了如何使用Java连接到redis&#xff0c;这期我们来学习如何在java中使用redis中的一些命令 1. set/get 可以看到jedis类中提供了很多set方法 public static void test1(Jedis jedis) {jedis.flushAll();jedis.set("key1", "v1");jedis.set(&q…

解决OSS存储桶未创建导致的XML错误

前言 在Java开发中&#xff0c;集成对象存储服务&#xff08;OSS&#xff09;时&#xff0c;开发者常会遇到一个令人困惑的错误提示&#xff1a; “This XML file does not appear to have any style information associated with it. The document tree is shown below.” 此…

Spring 表达式语言(SpEL)深度解析:从基础到高级实战指南

目录 一、SpEL是什么&#xff1f;为什么需要它&#xff1f; 核心价值&#xff1a; 典型应用场景&#xff1a; 二、基础语法快速入门 1. 表达式解析基础 2. 字面量表示 3. 属性访问 三、SpEL核心特性详解 1. 集合操作 2. 方法调用 3. 运算符大全 4. 类型操作 四、Sp…

算法导论第二十四章 深度学习前沿:从序列建模到创造式AI

第二十四章 深度学习前沿&#xff1a;从序列建模到创造式AI 算法的进化正在重新定义人工智能的边界 深度学习作为机器学习领域最活跃的分支&#xff0c;正以惊人的速度推动着人工智能的发展。本章将深入探讨五大前沿方向&#xff0c;通过原理分析、代码实现和应用场景展示&…

抽象工厂设计模式

1.问题背景&#xff1a; 现在有两个产品(Product)分别是手机壳(PhoneCase)和耳机(EarPhone)&#xff0c;但是他们会来自于各个生产厂商&#xff0c;比如说Apple和Android等等 那么至少会有四个产品&#xff0c;分别是安卓手机壳&#xff0c;安卓耳机&#xff0c;苹果手机壳&a…

GESP 3级 C++ 知识点总结

根据GESP考试大纲 (2024年3月版)&#xff0c;帮大家总结一下GESP 3级 C语言的知识点&#xff1a; 核心目标&#xff1a; 掌握C程序的基本结构&#xff0c;理解并能运用基础的编程概念解决稍复杂的问题&#xff0c;重点是函数、一维数组和字符串处理。 主要知识点模块&#x…

腾讯云主动型云蜜罐技术解析:云原生威胁狩猎的革新实践(基于腾讯云开发者社区技术网页与行业实践)

摘要 腾讯云主动型云蜜罐&#xff08;Active Cloud Honeypot&#xff09;通过动态诱捕机制和云原生架构&#xff0c;在威胁检测效率、攻击链还原深度、防御联动实时性等维度实现突破。相较于传统蜜罐&#xff0c;其核心优势体现在&#xff1a; 部署效率&#xff1a;分钟级完成…

企业微信wecom/jssdk的使用(入门)

概述 记录一个企业微信jssdk的使用&#xff0c;因为要用到图片上传、扫描二维码等工具。项目是uniapp开发的h5项目&#xff0c;fastadmin&#xff08;thinkphp5&#xff09;后端 先看官方文档 https://developer.work.weixin.qq.com/document/path/90547#%E5%BA%94%E7%94%A8…

大零售生态下开源链动2+1模式、AI智能名片与S2B2C商城小程序的协同创新研究

摘要&#xff1a;在流量红利消退、零售形态多元化的背景下&#xff0c;大零售生态成为商业发展的新趋势。本文聚焦开源链动21模式、AI智能名片与S2B2C商城小程序在零售领域的协同应用&#xff0c;探讨其如何打破传统零售边界&#xff0c;实现流量变现与用户资产化。研究表明&am…

Scrapy全流程(一)

创建一个scrapy项目:scrapy startproject mySpider 生成一个爬虫:scrapy genspider douban movie.douban.com 提取数据:完善spider&#xff0c;使用xpath等方法 保存数据:pipeline中保存数据 2 创建scrapy项目 下面以抓取豆瓣top250来学习scrapy的入门使用&#xff1a;豆瓣…

【Elasticsearch】TF-IDF 和 BM25相似性算法

在 Elasticsearch 中&#xff0c;TF-IDF 和 BM25 是两种常用的文本相似性评分算法&#xff0c;但它们的实现和应用场景有所不同。以下是对这两种算法的对比以及在 Elasticsearch 中的使用情况&#xff1a; TF-IDF - 定义与原理&#xff1a;TF-IDF 是一种经典的信息检索算法&am…

【QT】控件二(输入类控件、多元素控件、容器类控件与布局管理器)

文章目录 1.输入类控件1.1 LineEdit1.2 Text Edit1.3 Combo Box1.4 SpinBox1.5 Date Edit & Time Edit1.6 Dial1.7 Slider 2. 多元素控件2.1 List Widget2.2 Table Widget2.3 Tree Widget 3. 容器类控件3.1 Group Box3.2 Tab Widget 4. 布局管理器4.1 垂直布局4.2 水平布局…

【Docker基础】Docker镜像管理:docker pull详解

目录 1 Docker镜像基础概念 1.1 什么是Docker镜像&#xff1f; 1.2 镜像与容器的关系 1.3 镜像仓库(Registry) 2 docker pull命令详解 2.1 基本语法 2.2 参数解释 2.3 拉取镜像的基本流程 2.4 镜像分层结构解析 3 docker pull实战指南 3.1 基本使用示例 3.2 指定镜…