当前位置: 首页 > 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,在不同的平台生成相同的界面。

http://www.xdnf.cn/news/288379.html

相关文章:

  • 深度学习里程碑:AlexNet 架构解析与核心技术详解
  • 【深度学习|学习笔记】Deep Belief Network(DBN,深度置信网络)起源、原理、发展和应用(附代码)
  • 【KWDB 创作者计划】基于 ESP32 + KWDB 的智能环境监测系统实战
  • 高可用架构设计——故障响应
  • Red Hat6.4环境下搭建DHCP服务器
  • 第六章 流量特征分析-蚁剑流量分析(玄机靶场系列)
  • MCP原理详解及实战案例(动嘴出UI稿、3D建模)
  • Linux系统安装PaddleDetection
  • 基于CBOW模型的词向量训练实战:从原理到PyTorch实现
  • 使用AI 将文本转成视频 工具 介绍
  • 实验-数字电路设计2-复用器和七段数码管(数字逻辑)
  • 在Ubuntu系统中安装桌面环境
  • 路由器详细讲解
  • Docker —— 隔离的基本操作(1)
  • SpringCloud GateWay网关
  • 排序用法(Arrays.sort)
  • AI笔记-1
  • Qwen2_5-Omni-3B:支持视频、音频、图像和文本的全能AI,可在本地运行
  • 【Flask】ORM模型以及数据库迁移的两种方法(flask-migrate、Alembic)
  • 【全队项目】智能学术海报生成系统PosterGenius--前后端系统介绍
  • Vuex使用指南:状态管理
  • Leetcode:回文链表
  • GGD独立站的优势
  • 备战蓝桥杯国赛第一天-atcoder-beginner-contest404
  • Python异步编程进阶:深入探索asyncio高级特性
  • 从零开始开发纯血鸿蒙应用之NAPI
  • Linux的web服务器的部署及优化
  • 关于浏览器页面自动化操作
  • Python 矩阵运算:从理论到实践
  • 五大神经网络开发实战:从入门到企业级部署