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

虚拟dom是什么,他有什么好处

本编,博主将从虚拟dom是什么引出,为什么需要虚拟dom虚拟dom的益处为什么需要Diff算法for循环中key的作用是什么

1.虚拟dom是什么
虚拟dom就是以js对象的形式表示真实dom结构
例如

const newVNode = {type: 'div',children: [{ type: 'p', children: '4' },{ type: 'p', children: '5' },{ type: 'p', children: '6' }]
}

很明显能看出来,这个虚拟dom描述的其实就是,外层容器是一个div,有三个子标签p

<div><p>4</p><p>5</p><p>6</p>
</div>

2.那为什么需要虚拟dom呢
首先就是操作真实dom的速度要远低于操作js对象的速度。
在这里插入图片描述

但是就算操作js对象的速度要快,最终不是还需要操作真实dom进行更新吗,这不是多此一举吗,需要先操作一遍虚拟dom,在操作真实dom,这不是多出了一个步骤吗。
这是因为在vuereact这种框架中无法直接定位变化的那个元素,它的细粒度是组件级别的,所以说需要对比更新前后的虚拟dom找不同,在更新不同。
例如

// 旧的虚拟 DOM(旧 vnode)
const oldVNode = {type: 'div',children: [{ type: 'p', children: '1', key: 1 },{ type: 'p', children: '2', key: 2 },{ type: 'p', children: '3', key: 3 }]
}// 新的虚拟 DOM(新 vnode)
const newVNode = {type: 'div',children: [{ type: 'p', children: '1', key: 1 },{ type: 'p', children: '2', key: 2 },{ type: 'p', children: '6', key: 3 }]
}

看这两个新旧虚拟dom,就是要更新的是什么,肯定是更新最后一个p标签。

这里的找不同进行更新就是diff算法
diff算法
我们知道操作真实dom的效率太低,那就应该尽量减少操作真实dom的次数
所以diff出现的目的就是为了复用dom,减少操作真实dom的次数
比如上面新旧dom树,我们就可以复用第一和第二p标签,第三个p标签单独更新即可,所以说前两个可以复用,第三个需要更新就是不能复用吗,并不是这样,我们发现,第三个P标签只需要更新文本节点即可,所以第三个标签也是可复用标签,只需要更新其文本就行。
那么diff落实到代码是如何实现dom的复用呢
还是用上面的那个新旧虚拟dom

// 旧的虚拟 DOM(旧 vnode)
const oldVNode = {type: 'div',children: [{ type: 'p', children: '1'},{ type: 'p', children: '2'},{ type: 'p', children: '3'}]
}// 新的虚拟 DOM(新 vnode)
const newVNode = {type: 'div',children: [{ type: 'p', children: '1'},{ type: 'p', children: '2'},{ type: 'p', children: '6'}]
}

真实的dom算法比较复杂,我们这里就模拟一个简单的diff。

function patchChildren(n1, n2) {const oldChildren = n1.childrenconst newChildren = n2.childrenfor (let i = 0; i < oldChildren.length; i++) {//复用dom进行更新patch(oldChildren[i], newChildren[i])}
}

代码很简单,就是一个一个更新,这里的patch就是更新操作,不用管他具体实现,只需要知道它的作用是复用更新即可。
这样就是无脑更新,我们在把虚拟dom的顺序变一下

// 旧的虚拟 DOM(旧 vnode)
const oldVNode = {type: 'div',children: [{ type: 'p', children: '1'},{ type: 'p', children: '2'},{ type: 'p', children: '3'},]
}// 新的虚拟 DOM(新 vnode)
const newVNode = {type: 'div',children: [{ type: 'p', children: '3'},{ type: 'p', children: '2'},{ type: 'p', children: '1'}]
}

如果我们依然采用上面那种方式更新的话,就会造成复用的dom差异过大,更新的开销更大。
在这里插入图片描述

很明显,我们肯定是想要右边那种复用方式,那么如何实现呢,就需要用到key了

// 加了key熟悉的旧的虚拟 DOM(旧 vnode)
const oldVNode = {type: 'div',children: [{ type: 'p', children: '1', key: 1},{ type: 'p', children: '2', key: 2},{ type: 'p', children: '3', key: 3},]
}

然后打乱旧vnode的顺序,成为新vnode

// 新的虚拟 DOM(新 vnode)
const newVNode = {type: 'div',children: [{ type: 'p', children: '3', key: 3},{ type: 'p', children: '2', key: 2},{ type: 'p', children: '1', key: 1}]
}

然后在写一下新版本的diff算法

function patchChildren(n1, n2) {const oldChildren = n1.childrenconst newChildren = n2.childrenfor (let i = 0; i < oldChildren.length; i++) {//复用dom进行更新const fu_use_dom = oldChildren.find(item => item.key == newChildren.key)patch(fu_use_dom, newChildren[i])}
}

这样一来我们就可以实现更好的复用,这个就是diff算法中key的作用,作为虚拟dom节点的标识,利于diff更新过程,找到正确复用的dom。

另一个好处就是跨平台
2.跨平台
我们这个js在很多平台,都支持,但是不同的平台,操作界面的方式可能不一样,浏览器是操作dom,但是别的可能不是dom,但是我们通过虚拟dom就能知道我最终要生成的界面长什么样子,只需要在不同平台,采取对应平台的渲染方式,就可以做到一套虚拟dom,在不同的平台生成相同的界面。

相关文章:

  • 【YOLO11改进】改进Conv、颈部网络STFEN、以及引入PIOU用于小目标检测!
  • 基于 jQuery 实现复选框全选与选中项查询功能
  • Python实例题:Python法拍网数据
  • C与指针——常见库函数
  • 51单片机入门教程——蜂鸣器播放天空之城
  • AI小智本地前后端部署
  • mysql-索引特性和事务管理
  • 分析atoi(),atol()和atof()三个函数的功能
  • C语言高频面试题——嵌入式系统去访问某特定的内存位置
  • 技术犯规计入个人犯规吗·棒球1号位
  • 2022年408真题及答案
  • 国内短剧 vs. 海外短剧系统:如何选择?2025年深度对比与SEO优化指南
  • RAGEN 简介:基于强化学习的智能体生成; StarPO框架:状态 - 思考 - 行动 - 奖励策略
  • 架构进阶:什么是数据架构,如何理解数据架构?(华为)
  • FOC算法开环控制基础
  • springboot单体项目的执行流程
  • Hi3516A的gpio控制备忘
  • 如何设计一个为QStackWidget的界面切换动画?
  • AI Agent 要用到的技术
  • /etc/kdump.conf 配置详解
  • 青岛双星名人集团董事长发公开信称家人逼迫交出管理权?公司回应
  • 言短意长|党政主官如何塑造流量城市?
  • “五一”假期全社会跨区域人员流动量超14.65亿人次
  • 日本来信|劳动者的书信④
  • “五一”假期第三天,预计全社会跨区域人员流动量超2.8亿人次
  • 包揽金银!王宗源、郑九源夺得跳水世界杯总决赛男子3米板冠亚军