前端技能树,面试复习第 27 天—— React Diff 算法的原理,和 Vue 有什么区别 | 虚拟 DOM | key 的原理,为什么要用

1. 对虚拟 DOM 的理解?虚拟 DOM 主要做了什么?虚拟 DOM 本身是什么?

从本质上来说,Virtual Dom 是一个 JavaScript 对象,通过对象的方式来表示 DOM 结构。将页面的状态抽象为 JS对象的形式,配合不同的渲染工具,使跨平台渲染成为可能。通过事务处理机制,将多次 DOM 修改的结果一次性的更新到页面上,从而有效的减少页面渲染的次数,减少修改 DOM 的重绘重排次数,提高渲染性能。

虚拟 DOM 是对 DOM 的抽象,这个对象是更加轻量级的对 DOM 的描述。它设计的最初目的,就是更好的跨平台,比如 node.js 就没有 DOM,如果想实现 SSR,那么一个方式就是借助虚拟 dom,因为虚拟 dom 本身是 js 对象。 在代码渲染到页面之前,vue 或者 react 会把代码转换成一个对象(虚拟DOM)。以对象的形式来描述真实dom结构,最终渲染到页面。在每次数据发生变化前,虚拟 dom 都会缓存一份,变化之时,现在的虚拟 dom 会与缓存的虚拟 dom 进行比较。在 vue 或者 reac t内部封装了diff 算法,通过这个算法来进行比较,渲染时修改改变的变化,原先没有发生改变的通过原先的数据进行渲染。

另外现代前端框架的一个基本要求就是无须手动操作 DOM,**一方面是因为手动操作 DOM 无法保证程序性能,多人协作的项目中如果 review 不严格,可能会有开发者写出性能较低的代码,**另一方面更重要的是省略手动 DOM 操作可以大大提高开发效率。

为什么要用 Virtual DOM:

(1)保证性能下限,在不进行手动优化的情况下,提供过得去的性能

下面对比一下修改DOM时真实 DOM 操作和 Virtual DOM 的过程,来看一下它们重排重绘的性能消耗∶

  • 真实DOM∶ 生成 HTML 字符串+ 重建所有的 DOM 元素
  • Virtual DOM∶ 生成 vNode+ DOMDiff +必要的 DOM 更新

Virtual DOM 更新 DOM 的准备工作耗费更多的时间,也就是 JS 层面,相比于更多的 DOM 操作它的消费是极其便宜的。

尤雨溪在社区论坛中说道∶ 框架给你的保证是,你不需要手动优化的情况下,我依然可以给你提供过得去的性能。

(2)跨平台

Virtual DOM 本质上是 JavaScript 的对象,它可以很方便的跨平台操作,比如服务端渲染、uniapp 等。

2. React diff 算法的原理是什么?

实际上,diff 算法探讨的就是虚拟 DOM 树发生变化后,生成 DOM 树更新补丁的方式。它通过对比新旧两株虚拟 DOM 树的变更差异,**将更新补丁作用于真实 DOM,**以最小成本完成视图更新。

具体的流程如下:

  • 真实的 DOM 首先会映射为虚拟 DOM;
  • 当虚拟 DOM 发生变化后,就会根据差距计算生成 patch(补丁),这个 patch 是一个结构化的数据,内容包含了增加、更新、移除等;
  • 根据 patch 去更新真实的 DOM,反馈到用户的界面上。

一个简单的例子:

import React from 'react'
export default class ExampleComponent extends React.Component {
  render() {
    if(this.props.isVisible) {
       return <div className="visible">visbile</div>;
    }
     return <div className="hidden">hidden</div>;
  }
}

这里,首先假定 ExampleComponent 可见,然后再改变它的状态,让它不可见 。映射为真实的 DOM 操作是这样的,React 会创建一个 div 节点。

<div class="visible">visbile</div>

当把 visbile 的值变为 false 时,就会替换 class 属性为 hidden,并重写内部的 innerText 为 hidden。这样一个生成补丁、更新差异的过程统称为 diff 算法。

Diff算法的三个策略

diff算法可以总结为三个策略,分别从树、组件及元素三个层面进行复杂度的优化:

  • 树: 只对同一层次的节点进行比较
  • 组件: class 一致,则默认为相似的树结构;不是则直接放入补丁中。只要父组件类型不同,就会被重新渲染。
  • 元素/节点:通过标记的 key 值进行对比。

策略一:忽略节点跨层级操作场景,提升比对效率。(基于树进行对比)

这一策略需要进行树比对,即对树进行分层比较。树比对的处理手法是非常“暴力”的,即两棵树只对同一层次的节点进行比较,如果发现节点已经不存在了,则该节点及其子节点会被完全删除掉,不会用于进一步的比较,这就提升了比对效率。

策略二:如果组件的 class 一致,则默认为相似的树结构,否则默认为不同的树结构。(基于组件进行对比)

在组件比对的过程中:

  • 如果组件是同一类型则进行树比对;
  • 如果不是则直接放入补丁中。

只要父组件类型不同,就会被重新渲染。这也就是为什么 shouldComponentUpdate、PureComponent 及 React.memo 可以提高性能的原因。

策略三:同一层级的子节点,可以通过标记 key 的方式进行列表对比。(基于节点进行对比)

元素比对主要发生在同层级中,通过标记节点操作生成补丁。**节点操作包含了插入、移动、删除等。其中节点重新排序同时涉及插入、移动、删除三个操作,所以效率消耗最大,**此时策略三起到了至关重要的作用。通过标记 key 的方式,React 可以直接移动 DOM 节点,降低内耗。

3. React key 是干嘛用的 为什么要加?key 主要是解决哪一类问题的

Key 是 React 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识。在开发过程中,我们需要 保证某个元素的 key 在其同级元素中具有唯一性`。

在 React Diff 算法中 React 会借助元素的 Key 值来 判断该元素是新近创建的还是被移动而来的元素,从而减少不必要的元素重渲染此外,React 还需要借助 Key 值来判断元素与本地状态的关联关系。

注意事项:

  • key值一定要和具体的元素一一对应;

  • 尽量不要用数组的 index 去作为 key;

  • **不要在 render 的时候用随机数或者其他操作给元素加上不稳定的 key,**这样造成的性能开销比不加 key 的情况下更糟糕。

  • 用组件唯一的 id(一般由后端返回)作为它的 key,实在没有的情况下,可以在获取到列表的时候通过某种规则为它们创建一个 key,并保证这个 key 在组件整个生命周期中都保持稳定。

  • **别用 index 作为 key,和没写基本上没区别,因为不管你数组的顺序怎么颠倒,index 都是 0, 1, 2 这样排列,导致 Vue 会复用错误的旧子节点,做很多额外的工作。

  • 千万别用随机数或者时间戳作为 key,不然旧节点会被全部删掉,新节点重新创建。

使用数组下标作为 v-for 的 key 值所带来的的问题

在用 v-for 更新已渲染的元素列表的时候,会使用就地复用的策略;
也就是说列表数据修改的时候,他会根据key值去判断某个值是否改变了,如果改变了就重新渲染,不然就复用之前的元素。v-for 可以使用数据本身所具有的唯一值作为 key,也可以使用索引 index 作为 key

eg. 当我们修改 list,向其中插入一条数据时: image.png
可见,除了 name 为 aa 的那条数据的 key 值没变外,另外两个都变了,也就是说 aa 可以复用, 而另外两条数据虽然值没变,但 key 值改变了,需要重新渲染,这种效率是很低的。这时我们可以使用 list 的 id 作为 key 来提高效率。

4. 虚拟 DOM 的引入与直接操作原生 DOM 相比,哪一个效率更高,为什么

虚拟 DOM 相对原生的 DOM 不一定是效率更高,如果只修改一个按钮的文案,那么虚拟 DOM 的操作无论如何都不可能比真实的 DOM 操作更快。在首次渲染大量 DOM 时,由于多了一层虚拟 DOM 的计算,虚拟 DOM 也会比innerHTML 插入慢。它能保证性能下限,在真实 DOM 操作的时候进行针对性的优化时,还是更快的。所以要根据具体的场景进行探讨。

在整个 DOM 操作的演化过程中,其实主要矛盾并不在于性能,而在于开发者写得爽不爽,在于研发体验/研发效率。虚拟 DOM 不是别的,正是前端开发们为了追求更好的研发体验和研发效率而创造出来的高阶产物。虚拟 DOM 并不一定会带来更好的性能,React 官方也从来没有把虚拟 DOM 作为性能层面的卖点对外输出过。虚拟 DOM 的优越之处在于,它能够在提供更爽、更高效的研发模式(也就是函数式的 UI 编程方式)的同时,仍然保持一个还不错的性能。

5. React 与 Vue 的 diff 算法有何不同?

diff 算法是指生成更新补丁的方式,主要应用于虚拟 DOM 树变化后,更新真实 DOM。所以 diff 算法一定存在这样一个过程:触发更新 → 生成补丁 → 应用补丁。

React 的 diff 算法,触发更新的时机主要在 state 变化与 hooks 调用之后。此时触发虚拟 DOM 树变更遍历,采用了深度优先遍历算法。
但传统的遍历方式,效率较低。为了优化效率,使用了分治的方式。将单一节点比对转化为了 3 种类型的比对,分别是树、组件及元素,以此提升效率。

  • 树比对:由于网页视图中较少有跨层级节点移动,两株虚拟 DOM 树只对同一层次的节点进行比较。
  • 组件比对:如果组件是同一类型,则进行树比对,如果不是,则直接放入到补丁中。
  • 元素比对:主要发生在同层级中,通过标记节点操作生成补丁,节点操作对应真实的 DOM 剪裁操作。

以上是经典的 React diff 算法内容。

自 React 16 起,引入了 Fiber 架构。为了使整个更新过程可随时暂停恢复,节点与树分别采用了 FiberNode 与 FiberTree 进行重构。fiberNode 使用了双链表的结构,可以直接找到兄弟节点与子节点。
整个更新过程由 current 与 workInProgress 两株树双缓冲完成。workInProgress 更新完成后,再通过修改 current 相关指针指向新节点。

Vue 的整体 diff 策略与 React 对齐,虽然缺乏时间切片能力, 但这并不意味着 Vue 的性能更差,因为在 Vue 3 初期引入过,后期因为收益不高移除掉了。除了高帧率动画,在 Vue 中其他的场景几乎都可以使用 防抖和节流去提高响应性能。

Vue源码:虚拟DOM和diff算法,前端程序员面试必备的知识点 外链图片转存中…(img-0QxWSql5-1712008384196)][外链图片转存中…(img-Hkjt9b2N-1712008384197)][外链图片转存中…(img-6spP3RbQ-1712008384197)][外链图片转存中…(img-6mPcbOAf-1712008384197)][外链图片转存中…(img-mpVcH8Dd-1712008384198)][外链图片转存中…(img-cXn4mDoL-1712008384198)] 阅读详情

相关推荐

vue的diff和react的diff原理及其区别(纯文字)

vue的diff和react的diff原理及其区别

sxww_zyt的博客 742

图解 React diff 算法

diff 计算发生在更新阶段,当第一次渲染完成后,就会产生 Fiber 树,再次渲染的时候(更新),就会拿新的 JSX 对象(vdom)和旧的 FiberNode 节点进行一个对比,再决定如何来产生新的 FiberNode,它的目标是尽可能的复用已有的 Fiber 节点。这个就是 diff 算法。在 React 中整个 diff 分为单节点 diff 和多节点 diff。所谓单节点是指新的节点为单一节点,但是旧节点的数量是不一定的。判断 key 是否相同。

qq_42944740的博客 2041

前端面试进阶路线:一年半经验如何系统备战与突破

前端面试的考察重点随经验阶段而变化,对于一年半经验的开发者而言,面试官不再满足于基础API的调用,而是更关注对原理的深入理解与工程实践的沉淀。从浏览器渲染机制、事件循环到React的Fiber架构与Hooks原理,再到微前端、性能优化等热点方向,面试的本质是检验候选人是否具备“知其然更知其所以然”的技术素养。同时,项目深挖与场景题成为区分度最高的环节,如何把业务需求转化为技术方案、如何用数据量化优化成果,都是面试官评判工程能力的核心依据。从手写代码到算法刷题,再到面试复盘与心态管理,系统化的备战策略能显著提

weixin_33875564的博客 1117

【快手一面二面实习offer面试总结】

写在前面: 就其实自己是没有写面试总结这个习惯的,暑假去百度实习的时候,就有朋友让我写一下面试总结呀之类的,但是面试时间真的挺久(视频面试),好多东西都忘了,一直到实习回来就把学的新的技术挣了12篇博客发了,没有我预期中的爆炸访问量,demo特没有很多访问量,我就好奇是不是因为我么有设置付费(哈哈哈哈,调皮一下)。 其实从暑假开始实习,自己就规划好了,开学了在11月份左右找实习,再去北京(对了,北京真的挺好的,除了房租贵,车堵云云)。然后从国庆开始,review了一下react知识,学了Typescript

qq_43955202的博客 1万+

2025美团前端面试高频题解析:从JS原理到性能优化

前端面试考察的不再是API记忆,而是对技术原理与工程落地的综合理解。以JavaScript为例,闭包、事件循环、Promise手写题背后,是执行上下文与异步调度机制的系统掌握;Vue和React的源码追问,则要求候选人从响应式Proxy、diff算法与Hooks调用链等底层机制推导设计取舍。理解这些原理,不仅能应对大厂高频考题,更能指导真实业务中的性能优化与代码质量提升。从浏览器缓存策略到webpack/Vite构建流程,从XSS防御到监控体系,面试官最终考察的是候选人解决实际问题的能力。2025年美团前端

weixin_34218890的博客 321

Vue的Diff算法与React的Diff算法有何不同?

Vue 和 React 的 Diff 算法各有其特点和优化策略。Vue 强调同级比较和简单的节点替换,而 React 则采用分层比较和组件标识的方式。两者在性能和使用场景上也有所不同,开发者可以根据项目的需求选择合适的框架。

祈澈菇凉 1264

React高频面试题核心考点解析:从虚拟DOM到Hooks与性能优化

虚拟DOM、Hooks与状态管理是React技术体系的核心。理解其底层原理,例如diff算法如何通过同层比较与key优化将复杂度降至O(n),以及闭包陷阱对副作用执行的影响,是掌握React的关键。这些技术价值在于提升大型应用的可维护性与渲染性能,并广泛应用于组件通信、路由管理、服务端渲染等典型工程场景。在React 18并发特性与AI融合的前端趋势下,深入掌握这些概念能帮助开发者应对复杂的面试考察。本文基于一份React高频面试题集,系统拆解虚拟DOM、diff算法、Hooks使用边界、性能优化排查顺序等

weixin_34242331的博客 381

前端面试八股文:从考点地图到源码手写的复习指南

在前端开发中,很多基础概念构成了日常编码与面试考察的共同底座。比如JavaScript闭包与作用域链决定变量生命周期,事件循环与Promise约束异步执行顺序,虚拟DOM和diff算法关系着框架渲染效率。理解这些概念背后的原理,不仅有助于排查内存泄漏、优化列表渲染,还能在构建工具、性能优化和项目架构中做出更合理的设计决策。无论是处理滚动场景的防抖节流、手写Promise.all的边界条件,还是分析Vue响应式与React不可变数据的设计取舍,都离不开扎实的底层认知。通过把零散考点整理为HTML/CSS/JS

weixin_29015899的博客 140

树莓派计算模块摄像头连接与配置全攻略:从硬件跳线到软件驱动

在嵌入式视觉项目中,摄像头模组的连接与驱动是图像采集和视频分析的基础。其核心原理是通过CSI-2高速串行接口协议传输图像数据,并依赖I2C总线进行传感器寄存器配置。这一技术方案的价值在于为工业控制、机器人等嵌入式设备提供了稳定、高性价比的视觉感知能力。在实际应用中,开发者常面临摄像头无法识别、I2C通信失败等挑战,尤其是在使用树莓派计算模块时,其硬件接口需要通过I/O板引出,配置过程涉及设备树参数调整等关键步骤。本文聚焦于解决这些实际问题,详细拆解了从硬件连接到软件驱动的完整流程,特别是针对CM4、CM3+

weixin_29184075的博客 332

使用网分对晶体ESR/L1/C1/C0进行测量计算

Use R&amp;S Vector Network Analyzer test XTAL ESR/L1/C1/C0 測量方法:使用儀器的Port1端口,測量XTAL的S11,通過諧振的參數計算出ESR/L1/C1/C0的值。 實際晶體的等效模型:通常方便晶體分析,使用下圖(b)的等效模型,但實際測量發現晶體存在多個串聯諧振點,實際等效模型更接近(c)。 儀器測量到的S11,其中M...

qq_39138630的博客 2081

Sciter教程_00_创建HelloWorld工程

本教程记录Sciter工程的创建和编译运行的过程。

qq_36707072的博客 2277

STM32U575 ADC+DMA+UART数据采集实战:CubeMX配置避坑与代码实现

在嵌入式开发中,ADC采集与DMA传输是提升系统实时性的关键技术。通过DMA将ADC数据直接搬运到内存,可大幅降低CPU占用,实现高效连续采样。结合UART的DMA发送,能进一步解放CPU,适用于工业采集、信号监测等场景。本文以STM32U575为例,详解CubeMX中ADC、DMA、UART的配置要点,包括时钟树、DMAMUX映射、循环模式等,并给出代码实现与常见问题排查,帮助开发者快速构建稳定的数据采集链路。

weixin_29194255的博客 167

PCB设计之ODB++文件格式详解

ODB++(Open Database++)是一种广泛应用于PCB(印制电路板)设计和制造领域的开放数据交换格式。它由Valor Computerized Systems(现为Siemens EDA的一部分)开发,旨在替代传统的Gerber文件格式,提供更完整、结构化的制造数据,从而优化PCB设计到生产的流程。ODB++通过结构化数据整合了PCB设计到制造的全流程信息,显著提高了生产效率和准确性。尽管存在一定的兼容性挑战,但其在复杂项目和高可靠性场景中的价值不可替代。

ZZcppc的博客 1万+

检索增强生成(RAG)、微调(Fine-tuning)与知识蒸馏(Knowledge Distillation):核心差异与技术选型指南

在自然语言处理(NLP)领域,大型预训练语言模型(如GPT、BERT系列)的崛起彻底改变了技术生态。面对实际业务场景中模型效果优化与资源效率平衡的永恒命题,开发者主要依赖三大技术路径:检索增强生成(Retrieval-Augmented Generation, RAG)、模型微调(Fine-tuning)和知识蒸馏(Knowledge Distillation)。本文将通过技术原理拆解、典型应用场景对比和实战选型策略三个维度,深入解析这三种技术的本质差异。

fudaihb的博客 1826

最新Anaconda3的安装配置及使用教程(详细过程)

最新Anaconda3安装使用Anaconda下载方式一:官网下载方式二:清华镜像下载(推荐)Anaconda安装 Anaconda是一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项 Anaconda + Jupyter 基本上已经是大部分机器学习/数据分析等开发者标配的开发环境, 不多介绍,直接进去正题: Anaconda下载 方式一:官网下载 下载地址传送门: 官网首页:https://www.anaconda.com/ 官网下载页:https://www

HowieXue 薛永浩的博客 34万+

【Bug已解决】Context window exceeded / Token limit reached — Claude Code 上下文窗口超限解决方案

Claude Code 长会话中报上下文窗口/Token 超限,本质是对话历史、文件内容、工具结果累积超过 200K 上限。文中给出 /clear、/compact、分批读大文件、限制工具输出、配置 autoCompact 等完整方案。

一键难忘的博客 6725

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

上一篇: 【Web3 系列开发教程——创建你的第一个 NFT(3)】开始创建 NFT
下一篇: 前端技能树,面试复习第 28 天—— React 综合问题解析 | 实现一个全局 Dialog | React 的设计理念 | SSR | JSX 的原理 | HOC 高阶组件
蟹蟹蟹风流
蟹蟹蟹风流 优质创作者: 编程框架技术领域 优质创作者: 编程框架技术领域 领域专家: 前端开发技术领域 领域专家: 前端开发技术领域
博客等级 码龄11年 3万+粉丝 396原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蟹蟹蟹风流

期望和你分享一杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值