当前位置: 首页 > news >正文

Vue 虚拟DOM和DIff算法

一. 什么是虚拟DOM?

虚拟DOM(Virtual DOM), 本质上是用js对象来描述DOM结构的树形数据,然后再通过特定的render方法将其渲染成真是的DOM 

它的主要作用是: 

  • 减少直接操作真实DOM带来的性能开销
  • 通过比较新旧虚拟DOM差异,只对变化的部分进行最小化更新

通俗理解: 

虚拟DOM就是"用对象模拟HTML结构",每次状态变更先修改对象,最后再批量同步到页面上 

二.为什么需要虚拟DOM ?

  1. 减少DOM操作频率; 浏览器DOM操作是昂贵的(重排,重绘),虚拟DOM允许我们"批量修改", 
  2. 跨平台: 虚拟DOM并不依赖浏览器DOM,本质是纯对象,可用于SSR,原生渲染等 
  3. 提高渲染性能: 通过diff算法,可以最小化更新真实DOM,提升性能  

三.虚拟DOM与真实DOM的区别 

项目虚拟 DOM(VNode)真实 DOM(DOM Element)
本质JS 对象(树)浏览器提供的 HTML 节点(树)
创建开销非常小,内存中构建较大,操作会触发浏览器重排和重绘
渲染位置内存中显示在网页上
修改方式对象属性直接修改需要调用原生 DOM API
依赖平台与平台无关(跨平台)依赖浏览器 DOM API
 1.虚拟dom 
const vnode = {tag: 'div',data: { id: 'app' },children: [{ tag: 'p', data: {}, children: [], text: 'Hello' },{ tag: 'button', data: {}, children: [], text: 'Click me' }],text: undefined,elm: undefined
}
  •  tag: 标签名
  • data: 表示该标签的属性(如id)
  • children 表示子元素 
  • text 表示文本内容
  • elm 用于存储实际的DOM元素引用 
2.真实的dom 
<div id="app"><p>Hello</p><button>Click me</button>
</div>

四.Diff 算法 : 虚拟DOM更新的核心 

1.为什么需要Diff算法?

每当数据发生变化时,Vue会重新渲染组件并生成一个新的虚拟DOM树,然后,Vue会比较新旧虚拟DOM树之间的差异,计算出最小化的DOM更新(这个过程叫做DIff),这样做的目的是以避免频繁地操真实DOM,减少重排和重绘,提升性能

DIff的核心思想 

Vue的DIff算法通过一下几个核心思想来高效比较新旧Vnode树:  

  • 同层比较: Vue会在同一层级上进行比较,而不会跨层比较,这意味着Vue会首先比较根节点,接着比较每个子节点, 
  • 双端比较: Vue的Diff算法通过从两端开始对比(即从头和尾同时对比)来最大化复用节点,这样可以减少不必要的比较 
  • 复用节点: 只有当新旧节点是同类型(sameVnode)是,Vue才会尝试复用旧的DOM元素,否则就会销毁旧节点并创建新节点 
  • 最小化更新: 通过计算出差异后,Vue只更新那些发生变化的部分,而不是重新渲染整个DOM树 
同层比较与双端比较  

Vue的Diff算法先比较两个虚拟DOM树的根节点,然后从根节点触发,依次比较左右子节点,采用"双端对比"的策略,即: 

1. 从头开始比较: 比较oldStart和newStart; 

2. 从尾开始比较: 比较oldEnd和newEnd; 

3. 尝试优化节点的复用,最小化DOM操作. 

具体流程
  1. 更新触发: 当响应式数据发生变化时,Vue会触发相应的Watcher 
  2. 重新渲染: Watcher会触发render( ),生成新的虚拟DOM(VNode)
  3. Diff比较: Vue将新的VNode和旧的Vnode进行比对,使用DIff算法计算最小的变化; 
  4. Patch更新: 计算出差异后,Vue会通过patch操作将差异应用到真实DOM上 

2.同一个虚拟节点(sameVnde)判断

function sameVnode(a,b){return a.key===b.key && a.tag===b.tag 
}
  • key: 当Vnode的key一样是,表示它们是同一类型的节点,Vue可以复用这个节点 
  • tag: tag相同表示它们是相同类型的元素(如div,p,button等)  

 3.Vnode和真实DOM更新过程Patch函数

Vue在执行更新时,会通过patch函数来进行DOm的更新,patch函数的核心就是对比新旧虚拟DOM节点的差异,然后通过最小化更新来优化DOM操作

function patch(oldVnode, vnode) {if (!sameVnode(oldVnode, vnode)) {const parent = oldVnode.elm.parentNode;const newElm = createElm(vnode);parent.insertBefore(newElm, oldVnode.elm);parent.removeChild(oldVnode.elm);} else {patchVnode(oldVnode, vnode);}
}
  • sameVnode: 首先判断是否是同一个节点
  • patchVnode: 如果是同一个节点,则执行节点的属性,文本,子节点等的更新
  • createElm: 如果节点类型不同,Vue会销毁旧节点并创建新节点 
patchVnode处理节点更新 
1. 更新文本: 如果新旧节点都是文本节点,只需要更新文本内容
2.更新子节点: 如果有子节点,Vue会调用updateChildren来执行子节点的更新
3.更新属性: 如果节点的属性(如class,style等)有变化,Vue会通过原生DOMAPI更新这些属性 

五. 总结 

Vue通过虚拟DOM和Diff算法,极大地优化了性能,当数据发生变化时,Vue会生成新的虚拟DOM,通过DIff算法与旧的虚拟DOM树对比,最终只更新有变化的部分,从而减少了直接操作真实DOM的次数,提升了页面的响应速度,结合合理的性能优化策略,可以让Vue在大规模应用中也能保持高效的性能 

相关文章:

  • 学习Linux的第一天
  • 初试C++报错并解决记录
  • 栈Stack
  • Javascript学习笔记1——数据类型
  • 第20节:深度学习基础-反向传播算法详解
  • Linux的时间同步服务器
  • Python 中的 collections 库:高效数据结构的利器
  • node核心学习
  • dpm_sysfs_add
  • 构建良好的 AI 文化:解锁未来的密钥
  • C++日志系统实现(二)
  • 李沐《动手学深度学习》 | Softmax回归 - 分类问题
  • 牛客周赛90 C题- Tk的构造数组 题解
  • 2023年第十四届蓝桥杯省赛B组Java题解【 简洁易懂】
  • Python变量作用域陷阱:为什么函数内赋值会引发_局部变量未定义
  • Day 4:牛客周赛Round 91
  • I.MX6U的GPIO配置和LED点灯实验。
  • Dream it possible歌词中英文对照
  • 使用python写多文件#inlcude
  • GoLang基础(续)
  • 最长3个月免费住宿,南昌人才驿站(洪漂驿站)申请指南发布
  • 福建两名厅级干部履新,张文胜已任省委省直机关工委副书记
  • 旧宫新语|瑞琦:再探《古玩图》——清宫艺术品的前世与今生
  • 澎湃读报丨央媒头版头条集中刊发:大国应有的样子
  • 特朗普宣布提名迈克·沃尔兹为下一任美国驻联合国大使
  • 泽连斯基:美乌矿产协议将提交乌拉达批准