vue 和 react 底层采用的 diff 算法的区别
Vue 3 和 React 在底层 Diff 算法上的实现确实有一些区别,主要体现在设计理念、性能优化策略以及具体实现方式上。以下是对两者 Diff 算法差异的详细分析:
1. 总体设计理念
-
Vue 3 的 Diff 算法
Vue 3 的虚拟 DOM Diff 算法基于“双端比较”思想,并在 Vue 2 的基础上进行了优化。它更倾向于静态优化的编译时策略,通过分析模板结构尽可能减少运行时的对比工作。Vue 3 还引入了“静态提升”(Static Hoisting)和“Patch Flags”等机制,进一步提升性能。 -
React 的 Diff 算法
React 的 Diff 算法主要基于“单向递归”思想,采用一种启发式算法(Heuristic Algorithm)。它假设开发者会遵循一定的编码习惯(如尽量保持列表元素的稳定性),从而简化对比过程。React 的核心是“分层对比”(只对比同层节点)和“Key”机制来优化列表更新。
2. 核心 Diff 过程
-
Vue 3 的双端比较
Vue 3 在对比新旧虚拟 DOM 树时,使用了“首尾双指针”技术。具体步骤如下:- 从两端开始对比新旧节点(头对头、尾对尾、头对尾、尾对头),快速确定哪些节点可以复用。
- 如果两端对比无法匹配,则进入中间部分的“最长递增子序列”(Longest Increasing Subsequence, LIS)算法,来处理列表中节点的移动和更新。
- 通过 Patch Flags 标记动态变化的节点,只对标记过的部分进行精细更新。
这种双端比较的优势在于它能够更高效地处理列表中节点的移动,尤其是当列表长度较长时,性能表现更优。
-
React 的单向递归
React 的 Diff 过程是自顶向下、逐层对比的,主要步骤如下:- 同层比较:React 只比较同一层的节点,不跨层级比较。如果发现类型不同,直接删除旧节点并重建。
- Key 优化:对于列表渲染,React 依赖
key属性来识别节点是否可以复用。如果没有key,React 会按顺序逐个对比,可能导致大量不必要的 DOM 操作。 - 单向遍历:从头到尾逐一对比新旧节点,遇到不匹配时直接更新或重建。
React 的算法更简单直接,但对列表中节点的移动不够友好,尤其在缺少
key或key不稳定时,性能会显著下降。
3. 优化策略
-
Vue 3 的优化
- 编译时优化:Vue 3 在编译阶段会对模板进行静态分析,将静态内容提升(Static Hoisting),减少运行时对比开销。
- Patch Flags:标记动态节点(比如绑定了数据的节点),在 Diff 时只处理这些标记过的节点,跳过静态部分。
- LIS 算法:Vue 3 使用最长递增子序列优化列表更新,减少不必要的 DOM 操作,尤其在复杂列表场景下效果显著。
-
React 的优化
- Key 机制:React 依靠开发者手动提供
key来优化列表渲染,减少重新渲染的开销。 - Fiber 架构:React 16 之后引入的 Fiber 架构虽然不是 Diff 算法本身,但通过分片渲染(时间分片)间接提升了 Diff 的效率,允许中断和恢复更新过程。
- 启发式假设:React 假设大部分节点的顺序不会频繁变化,因此简化了算法逻辑,牺牲了一定的灵活性换取性能。
- Key 机制:React 依靠开发者手动提供
4. 适用场景与性能差异
-
Vue 3
- 优势:更适合复杂列表操作(插入、删除、移动等),因为双端比较和 LIS 算法能更高效地处理这些场景。
- 劣势:编译时的优化依赖模板语法,如果是纯手写
render函数,部分优化可能无法生效。
-
React
- 优势:算法简单,适合大多数简单场景,尤其是静态结构较多的应用。
- 劣势:对列表频繁变动支持不够友好,未提供
key或key不稳定时性能下降明显。
5. 总结对比
| 特性 | Vue 3 | React |
|---|---|---|
| 算法核心 | 双端比较 + LIS | 单向递归 + Key 优化 |
| 优化手段 | 编译时优化 + Patch Flags | Fiber + 启发式假设 |
| 列表处理 | 高效支持节点移动 | 依赖 Key,移动支持较弱 |
| 复杂度 | 实现较复杂,运行时更智能 | 实现简单,依赖开发者习惯 |
| 适用场景 | 复杂动态列表 | 简单结构或手动优化场景 |
结论
Vue 3 的 Diff 算法更加智能和高效,尤其在复杂场景下得益于编译时优化和双端比较的优势;而 React 的 Diff 算法更简单直接,依赖开发者通过 key 等手段手动优化。如果你的应用涉及大量动态列表操作,Vue 3 可能更有优势;如果更倾向于灵活的手动控制,React 可能是更好的选择。
下面我将用简化的 JavaScript 代码分别实现 Vue 3 和 React 的 Diff 算法的核心思路。由于完整的 Diff 算法实现涉及虚拟 DOM 的创建、挂载等复杂逻辑,这里只展示核心对比部分的伪代码,突出两者的差异。
简要实现
1. Vue 3 的双端比较 Diff 算法
Vue 3 使用双端比较结合最长递增子序列(LIS)来优化列表更新。这里我们简化实现双端比较部分,假设对比的是一个简单的节点数组。
// 双端比较 Diff
function vue3Diff(oldList, newList) {let oldStart = 0;let oldEnd = oldList.length - 1;let newStart = 0;let newEnd = newList.length - 1;while (oldStart <= oldEnd && newStart <= newEnd) {// 头对头if (oldList[oldStart] === newList[newStart]) {console.log(`复用节点: ${oldList[oldStart]}`);oldStart++;newStart++;}// 尾对尾else if (oldList[oldEnd] === newList[newEnd]) {console.log(`复用节点: ${oldList[oldEnd]}`);oldEnd--;newEnd--;}// 头对尾else if (oldList[oldStart] === newList[newEnd]) {console.log(`移动节点: ${oldList[oldStart]} 从头移动到尾`);oldStart++;newEnd--;}// 尾对头else if (oldList[oldEnd] === newList[newStart]) {console.log(`移动节点: ${oldList[oldEnd]} 从尾移动到头`);oldEnd--;newStart++;}// 无匹配,新增或删除else {console.log(`新增节点: ${newList[newStart]}`);newStart++;// 实际情况中可能需要查找并复用,或删除多余的旧节点}}// 处理剩余节点if (newStart <= newEnd) {console.log(`新增剩余节点: ${newList.slice(newStart, newEnd + 1)}`);}if (oldStart <= oldEnd) {console.log(`删除剩余节点: ${oldList.slice(oldStart, oldEnd + 1)}`);}
}// 测试
const oldList = ["A", "B", "C", "D"];
const newList = ["B", "A", "D", "E"];
vue3Diff(oldList, newList);
输出示例:
复用节点: B
移动节点: A 从头移动到尾
复用节点: D
新增节点: E
说明:
- 双端比较从两端开始,逐步缩小范围,优先复用节点。
- 如果节点位置变化(如 “A” 从头移到中间),会识别移动。
- 未实现 LIS 部分,但实际 Vue 3 在处理中间部分时会用 LIS 优化。
2. React 的单向递归 Diff 算法
React 的 Diff 算法依赖 key 进行列表对比,这里我们简化实现一个带 key 的单向遍历对比。
// 单向递归 Diff
function reactDiff(oldList, newList) {const oldMap = new Map(); // 用 Map 存储旧节点的 key 和索引oldList.forEach((item, index) => oldMap.set(item.key, { value: item.value, index }));let lastIndex = 0; // 用于记录上一个复用节点的位置,检测是否需要移动for (let i = 0; i < newList.length; i++) {const newItem = newList[i];const oldItem = oldMap.get(newItem.key);if (oldItem) {// 找到匹配的节点console.log(`复用节点: ${newItem.value} (key: ${newItem.key})`);if (oldItem.index < lastIndex) {console.log(`移动节点: ${newItem.value} 从 ${oldItem.index} 到 ${i}`);}lastIndex = oldItem.index;} else {// 未找到,新增节点console.log(`新增节点: ${newItem.value} (key: ${newItem.key})`);}}// 检查旧列表中需要删除的节点oldList.forEach((oldItem) => {if (!newList.some((newItem) => newItem.key === oldItem.key)) {console.log(`删除节点: ${oldItem.value} (key: ${oldItem.key})`);}});
}// 测试
const oldList = [{ key: "a", value: "A" },{ key: "b", value: "B" },{ key: "c", value: "C" },
];
const newList = [{ key: "b", value: "B" },{ key: "a", value: "A" },{ key: "d", value: "D" },
];
reactDiff(oldList, newList);
输出示例:
复用节点: B (key: b)
复用节点: A (key: a)
移动节点: A 从 0 到 1
新增节点: D (key: d)
删除节点: C (key: c)
说明:
- React 通过
key快速定位复用节点,按新列表顺序逐一对比。 - 如果节点顺序变化(如 “A” 从头移到中间),会检测到移动。
- 未提供
key时,React 会按顺序对比,这里假设都有key。
3. 代码对比与差异
| 方面 | Vue 3 双端比较 | React 单向递归 |
|---|---|---|
| 对比方式 | 从两端向中间逐步缩小 | 从头到尾单向遍历 |
| 移动检测 | 天然支持(头尾交叉对比) | 依赖 key 和索引对比 |
| 复杂度 | 更高(双指针 + LIS) | 较低(简单遍历) |
| 依赖 | 不依赖 key,算法自优化 | 强依赖 key,需手动提供 |
4. 注意事项
- 这只是简化实现,实际框架中的 Diff 算法会处理更多细节(如属性对比、组件更新、DOM 操作等)。
- Vue 3 的完整实现还包括编译时优化和 Patch Flags,这里未体现。
- React 的 Fiber 架构会将 Diff 分片执行,这里仅展示单次对比逻辑。
如果你有具体场景或想深入某部分(如 LIS 实现),可以告诉我,我再帮你扩展代码!
相关文章:
vue 和 react 底层采用的 diff 算法的区别
Vue 3 和 React 在底层 Diff 算法上的实现确实有一些区别,主要体现在设计理念、性能优化策略以及具体实现方式上。以下是对两者 Diff 算法差异的详细分析: 1. 总体设计理念 Vue 3 的 Diff 算法 Vue 3 的虚拟 DOM Diff 算法基于“双端比较”思想ÿ…...
VUE集成Live2d
VUE集成Live2d 目前基于大模型,可以实现一个桌面的3D动画小人,个人猜测可以简介这个项目进行实现 1-参考网址 试了很多项目,只有这个项目直观的把问题说清楚了 Live2D Vue3技术应用:https://blog.csdn.net/hh1233321/article/details/1406947…...
C++蓝桥杯基础篇(七)
片头 嗨~小伙伴们,大家好!今天我们来一起学习蓝桥杯基础篇(七),学习相关字符串的知识,准备好了吗?咱们开始咯! 一、字符与整数的联系——ASCII码 每个常用字符都对应一个-128~127的…...
常见的非关系性数据库
非关系型数据库(NoSQL)有多种类型,每种类型针对不同的应用场景提供了不同的存储和查询方式。以下是一些常见的非关系型数据库及其特点: 1. 键值数据库(Key-Value Stores) 特点:数据以键值对的…...
【Java反序列化测试】
Java反序列化测试 1. 识别反序列化入口点2. 构造探测Payload3. 发送Payload并观察结果4. 绕过可能的防护5. 自动化工具注意事项总结 Java反序列化测试: 1. 识别反序列化入口点 常见入口: HTTP请求参数(如POST数据、Cookie、Headersÿ…...
代码规范和简化标准
代码规范和简化标准是编写高质量、可维护、可扩展和可读代码的基本原则。遵循这些标准不仅能提高团队协作效率,还能减少出错的概率和后期维护的成本。以下是一些常见的代码规范和简化标准: 1. 命名规范 变量命名: 使用具有描述性的名称&…...
RabbitMQ怎么实现延时支付?
一、使用“死信队列”消息过期时间 1、原理: 设置消息”存活时间“,如果没有被及时消费,就会被丢弃到一个”死信队列“,然后消费者监听这个死信队列处理消息 2、步骤: 2.1、创建两个队列: 2.1.1、普通队…...
node项目前后端密码加密传输及存储方案
前端:使用crypto-js库的SHA256算法,包含用户注册时使用的邮箱加上自定义的secret key生成盐值,接着使用PBKDF2算法进行加密。最后将加密后的密码传给后端。 import CryptoJS from "crypto-js";export const encryptPassword (ema…...
迷你世界脚本方块接口:Block
方块接口:Block 彼得兔 更新时间: 2024-08-27 11:04:56 具体函数名及描述如下: 序号 函数名 函数描述 1 isSolidBlock(...) 是否是固体方块 2 isLiquidBlock(...) 是否是液体方块 3 isAirBlock(...) 是否是气体方块 4 getBl…...
el-input实现金额输入
需求:想要实现一个输入金额的el-input,限制只能输入数字和一个小数点。失焦数字转千分位,聚焦转为数字,超过最大值,红字提示 效果图 失焦 聚焦 报错效果 // 组件limitDialog <template><el-dialog:visible.s…...
双碳战略下的智慧能源实践:安科瑞储能管理系统助力企业绿色转型
在全球碳中和目标加速推进的背景下,中国“十四五”规划明确提出构建以新能源为主体的新型电力系统,储能技术成为支撑能源结构转型的核心要素。安科瑞储能能量管理系统作为企业级智慧能源解决方案的核心载体,凭借其技术创新与场景适配能力&…...
《鸢尾花数学大系:从加减乘除到机器学习》开源资源
《鸢尾花数学大系:从加减乘除到机器学习》开源资源 Gitee:https://gitee.com/higkoo/ bilibili:https://space.bilibili.com/513194466 GitHub:https://github.com/Visualize-ML...
本地部署HDFS集群
首先完成本地部署大数据集群前置准备,可参考: 本地部署大数据集群前置准备https://blog.csdn.net/m0_73641796/article/details/145994787?spm1001.2014.3001.5501 1.下载hadoop 下载Hadoop安装包,本文用的是hadoop-3.3.4.tar.gz 2. 集群…...
Windows 环境下 Nginx、PHP 与 ThinkPHP 开发环境搭建
Windows 环境下 Nginx、PHP 与 ThinkPHP 开发环境搭建 目录 安装 Nginx 和 PHP配置 Nginx配置 PHP启动服务ThinkPHP 配置常见问题排查 1. 安装 Nginx 和 PHP 安装 Nginx 访问 Nginx 官网 下载 Windows 版本解压到指定目录,如 C:\nginx 安装 PHP 访问 PHP 官网…...
10.【线性代数】—— 四个基本子空间
十、 四个基本子空间 1. 列空间 C ( A ) C(A) C(A) in R m R^m Rm2. 零空间 N ( A ) N(A) N(A) in R n R^n Rn3. 行空间 C ( A T ) C(A^T) C(AT) in R n R^n Rn4. 左零空间 N ( A T ) N(A^T) N(AT) in R m R^m Rm综述5. 新的向量空间 讨论矩阵 A m ∗ n A_{m*n} Am∗n…...
基于vue框架的游戏商城系统cq070(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
系统程序文件列表 项目功能:用户,分类,商品信息,游戏高手,游戏代练 开题报告内容 基于Vue框架的游戏商城系统开题报告 一、研究背景与意义 随着互联网技术的飞速发展和游戏产业的蓬勃兴起,游戏商城作为游戏产业链中的重要一环,迎来了前所…...
我代表中国受邀在亚马逊云科技全球云计算大会re:Invent中技术演讲
大家好我是小李哥,本名叫李少奕,目前在一家金融行业公司担任首席云计算工程师。去年5月很荣幸在全球千万名开发者中被选为了全球亚马逊云科技认证技术专家(AWS Hero),是近10年来大陆地区仅有的第9名大陆专家。同时作为…...
css3d放置的面板方向不对问题排查
以往在threejs左手坐标系下,cameranew THREE.Vector3(0, 0, 1),好像在贴css3d的时候从来不会出问题。而这次接到一个朋友是用右手坐标系的,camera默认不设置方向,则应该是(0,1,0) c…...
网络安全法与等级保护 PPT 精华汇总
资源描述 本资源文件为《网络安全法与等级保护》的PPT精华汇总,内容涵盖了网络安全法与等级保护的总体框架及相关标准规范。该PPT详细介绍了网络安全法与等级保护的各个章节和条款,并提供了基础类和应用类的相关标准文件,帮助读者全面了解和…...
chrome下载文件提示“贵组织屏蔽了该文件,因为它不符合安全政策” 安装chrome插件出现问题
查了一圈发现有如下解决方法 可逐一排查 1. 检查是否安装了阿里旺旺,会导致你无法安装chrome的插件。卸载阿里旺旺后,重启chrome即可 2. 注册表出现问题,删除\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome 下的 EnabledPlugins 文…...
linux磁盘满了怎么安全删除文件
df -h 通过df -h /dir 查看被占满的目录,dir替换为你的文件目录 du -sh * 进入被占满的目录,执行 du -sh * ,查看哪些文件占的磁盘大 查看占用磁盘最大的文件 du -sh * | sort -rh | head -n N N通常可以设置为10 有的docker容器文件太…...
探秘基带算法:从原理到5G时代的通信变革【十】基带算法应用与对比
文章目录 三、算法在现代通信系统中的应用3.1 5G 通信中的应用3.1.1 信道编码与调制解调3.1.2 大规模 MIMO 技术3.1.3 案例分析:5G 基站与终端实现 3.2 卫星通信中的应用3.2.1 抗干扰与纠错编码3.2.2 信号处理与调制解调3.2.3 案例分析:卫星通信系统实例…...
io学习----->标准io
思维导图: 一.io的作用 io是实现对文件的操作,把运行结果存到文件中,读取文件的数据,方便后期查询。 二.io的概念 io是指系统 和外部设备或用户之间的数据交互 I:input 表示数据从外部设备输入到内存中; O:output…...
go语言中字符串嵌套
在Go语言中,字符串嵌套通常是指在字符串中包含另一个字符串。可以通过以下几种方式实现: 1. 使用双引号和转义字符 如果需要在字符串中嵌套双引号,可以使用转义字符 \ 来表示内部的双引号。例如: s : "He said, \"He…...
2024-2025学年职业院校技能大赛“大数据应用开发”赛项竞赛样题-解析
2025年职业院校技术大赛-高职大数据应用开发赛项专题。 2024-2025学年广东省职业院校技能大赛“大数据应用开发”赛项竞赛样题1-任务B:离线数据处理_解析2024-2025学年广东省职业院校技能大赛“大数据应用开发”赛项竞赛样题2-任务B:离线数据处理_解析2…...
LeetCode 面试题 17.19. 消失的两个数字
LeetCode 面试题 17.19. 消失的两个数字 思路🧐: 运用位运算,我们先创建一个变量tmp,依次异或nums和1~N所有整数,此时就可以得到两个数的异或值。 然后通过右移操作,逐位检查tmp中的每一位,找到…...
KaiwuDB| Google Spanner 经典架构回顾
前言 大数据时代 ,随着移动互联网和物联网技术的发展 , 全球数据量呈现爆发式增长,已经远远超出集中式单机数据库的处理能力。CCF 数据库专委 2021 年发布的《“十四五”数据库发展趋势与挑战》显示, 各行各业海量数据的管理需求…...
拼电商客户管理系统
内容来自:尚硅谷 难度:easy 目 标 l 模拟实现一个基于文本界面的 《 拼电商客户管理系统 》 l 进一步掌握编程技巧和调试技巧,熟悉面向对象编程 l 主要涉及以下知识点: 类结构的使用:属性、方法及构造器 对象的创建与…...
Electron、Tauri及其它跨平台方案终极对比
Electron、Tauri及跨平台方案终极对比(2025版) 一、核心框架深度解析 1.1 Electron:Web技术的桌面霸主 技术架构 基于Chromium(浏览器内核) Node.js(后端运行时)的双进程架构,支持…...
WireGuard搭建网络,供整个公司使用
一、清理现有配置(如已有失败尝试) # 停止并删除现有 WireGuard 接口 sudo wg-quick down wg0 sudo rm -rf /etc/wireguard/wg0.conf# 验证接口已删除 (执行后应该看不到 wg0) ifconfig二、服务器端完整配置流程 1. 安装 WireGuard sudo apt update &…...
