对vue虚拟dom的研究
- Vue.js通过编译将template 模板转换成渲染函数(render ) ,执行渲染函数就可以得到一个虚拟节点树
- 在对 Model 进行操作的时候,会触发对应 Dep 中的 Watcher 对象。Watcher 对象会调用对应的 update 来修改视图。这个过程主要是将新旧虚拟节点进行差异对比,然后根据对比结果进行DOM操作来更新视图。
简单点讲,在Vue的底层实现上,Vue将模板编译成虚拟DOM渲染函数。结合Vue自带的响应系统,在状态改变时,Vue能够智能地计算出重新渲染组件的最小代价并应到DOM操作上。
patch(也叫做patching算法):虚拟DOM最核心的部分,它可以将vnode渲染成真实的DOM,这个过程是对比新旧虚拟节点之间有哪些不同,然后根据对比结果找出需要更新的的节点进行更新。这点我们从单词含义就可以看出, patch本身就有补丁、修补的意思,其实际作用是在现有DOM上进行修改来实现更新视图的目的。Vue的Virtual DOM Patching算法是基于Snabbdom的实现,并在些基础上作了很多的调整和改进
Virtual DOM 其实就是一棵以 JavaScript 对象( VNode 节点)作为基础的树,用对象属性来描述节点,实际上它只是一层对真实 DOM 的抽象。最终可以通过一系列操作使这棵树映射到真实环境上。
虚拟DOM的最终目标是将虚拟节点渲染到视图上。但是如果直接使用虚拟节点覆盖旧节点的话,会有很多不必要的DOM操作。例如,一个ul标签下很多个li标签,其中只有一个li有变化,这种情况下如果使用新的ul去替代旧的ul,因为这些不必要的DOM操作而造成了性能上的浪费。
为了避免不必要的DOM操作,虚拟DOM在虚拟节点映射到视图的过程中,将虚拟节点与上一次渲染视图所使用的旧虚拟节点(oldVnode)做对比,找出真正需要更新的节点来进行DOM操作,从而避免操作其他无需改动的DOM。
其实虚拟DOM在Vue.js主要做了两件事:
- 提供与真实DOM节点所对应的虚拟节点vnode
- 将虚拟节点vnode和旧虚拟节点oldVnode进行对比,然后更新视图
- 具备跨平台的优势
由于 Virtual DOM 是以 JavaScript 对象为基础而不依赖真实平台环境,所以使它具有了跨平台的能力,比如说浏览器平台、Weex、Node 等。
- 操作 DOM 慢,js运行效率高。我们可以将DOM对比操作放在JS层,提高效率。
因为DOM操作的执行速度远不如Javascript的运算速度快,因此,把大量的DOM操作搬运到Javascript中,运用patching算法来计算出真正需要更新的节点,最大限度地减少DOM操作,从而显著提高性能。
Virtual DOM 本质上就是在 JS 和 DOM 之间做了一个缓存。可以类比 CPU 和硬盘,既然硬盘这么慢,我们就在它们之间加个缓存:既然 DOM 这么慢,我们就在它们 JS 和 DOM 之间加个缓存。CPU(JS)只操作内存(Virtual DOM),最后的时候再把变更写入硬盘(DOM)
- 提升渲染性能
Virtual DOM的优势不在于单次的操作,而是在大量、频繁的数据更新下,能够对视图进行合理、高效的更新。
为了实现高效的DOM操作,一套高效的虚拟DOM diff算法显得很有必要。我们通过patch 的核心----diff 算法,找出本次DOM需要更新的节点来更新,其他的不更新。
Vue的diff算法是基于snabbdom改造过来的,仅在同级的vnode间做diff,递归地进行同级vnode的diff,最终实现整个DOM树的更新。因为跨层级的操作是非常少的,忽略不计,这样时间复杂度就从O(n3)变成O(n)。
diff 算法的实现过程
diff 算法本身非常复杂,实现难度很大。本文去繁就简,粗略介绍以下两个核心函数实现流程:
- patch(container,vnode) :初次渲染的时候,将VDOM渲染成真正的DOM然后插入到容器里面。
- patch(vnode,newVnode):再次渲染的时候,将新的vnode和旧的vnode相对比,然后之间差异应用到所构建的真正的DOM树上。
function createElement(vnode) {
var tag = vnode.tag
var attrs = vnode.attrs || {}
var children = vnode.children || []
if (!tag) {
return null
}
// 创建真实的 DOM 元素
var elem = document.createElement(tag)
// 属性
var attrName
for (attrName in attrs) {
if (attrs.hasOwnProperty(attrName)) {
// 给 elem 添加属性
elem.setAttribute(attrName, attrs[attrName])
}
}
// 子元素
children.forEach(function (childVnode) {
// 给 elem 添加子元素,如果还有子节点,则递归的生成子节点。
elem.appendChild(createElement(childVnode)) // 递归
}) // 返回真实的 DOM 元素
return elem
}
2.patch(vnode,newVnode)
这里我们只考虑vnode与newVnode如何对比的情况:
function updateChildren(vnode, newVnode) {
var children = vnode.children || []
var newChildren = newVnode.children || []
// 遍历现有的children
children.forEach(function (childVnode, index) {
var newChildVnode = newChildren[index]
// 两者tag一样
if (childVnode.tag === newChildVnode.tag) {
// 深层次对比,递归
updateChildren(childVnode, newChildVnode)
} else {
// 两者tag不一样
replaceNode(childVnode, newChildVnode)
}
}
)}
对vue虚拟dom的研究的更多相关文章
- Vue 虚拟Dom 及 部分生命周期初探
踏入前端,步入玄学 17年底至18年初附带做了vue的一些框架搭建,中途断断续续用了部分vue,时隔几个月后的工作又拾起vue,对于一些原理性的知识淡忘了,正值这段时间使用中遇到了一些坑,又拨了部分代 ...
- Es6语法+v-on参数相关+vue虚拟dom
Es6的语法 Es5:if和for 都没有块级作用域,函数function有作用域. Es6:加入let使得if和for有作用域 .建议: 在Es6中优先使用const,只有需要改变某一个标识符的时候 ...
- vue虚拟DOM源码学习-vnode的挂载和更新流程
代码如下: <div id="app"> {{someVar}} </div> <script type="text/javascript& ...
- vue 虚拟dom
https://segmentfault.com/a/1190000008291645 一个VNode的实例对象包含了以下属性 tag: 当前节点的标签名 data: 当前节点的数据对象 VNode可 ...
- vue虚拟dom原理
Virual DOM是用JS对象记录一个dom节点的副本,当dom发生更改时候,先用虚拟dom进行diff,算出最小差异,然后再修改真实dom. vue的virtual dom的diff算法是基于sn ...
- vue虚拟dom和diff算法
vue的虚拟dom和diff算法 1.虚拟dom 虚拟dom,我的理解就是通过js对象的方式来具体化每一个节点,把dom树上面的每个节点都变为对象里的一个元素,元素的子元素变为子节点,节点上面的cla ...
- 关于react虚拟DOM的研究
1.传统的前端是这样的,我在学校也都是这样做的,html(jsp)主要负责提供所有的DOM节点,而javascript负责动态效果,比如按钮点击,图片轮播等,这样的话javascript如何组织结构是 ...
- vue 源码学习三 vue中如何生成虚拟DOM
vm._render 生成虚拟dom 我们知道在挂载过程中, $mount 会调用 vm._update和vm._render 方法,vm._updata是负责把VNode渲染成真正的DOM,vm._ ...
- Vue之虚拟DOM
一.真实DOM和其解析流程? 浏览器渲染引擎工作流程都差不多,大致分为5步,创建DOM树——创建StyleRules——创建Render树——布局Layout——绘制Painting 第一步,用HTM ...
随机推荐
- cocos2dx基础篇(25) 简单碰撞检测
[3.x] 将数学类 CCPoint.CCRect 改为v3.x版本的 Vec2.Rect 就好了. [简单碰撞检测] 在一些游戏中经常会遇到碰撞检测的情况,如愤怒的小鸟飞出去后,是否与石头发生碰撞. ...
- 解决某些软件无法在parallels desktop虚拟机下运行
步骤1.打开注册表,点开始菜单,点运行,输入regedit.exe后回车 步骤2.找到HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System 步骤3.找到右边的V ...
- [深度应用]·Keras极简实现Attention结构
[深度应用]·Keras极简实现Attention结构 在上篇博客中笔者讲解来Attention结构的基本概念,在这篇博客使用Keras搭建一个基于Attention结构网络加深理解.. 1.生成数据 ...
- 【Python开发】【神经网络与深度学习】网络爬虫之图片自动下载器
python爬虫实战--图片自动下载器 之前介绍了那么多基本知识[Python爬虫]入门知识(没看的赶紧去看)大家也估计手痒了.想要实际做个小东西来看看,毕竟: talk is cheap show ...
- 【神经网络与深度学习】学习笔记:AlexNet&Imagenet学习笔记
学习笔记:AlexNet&Imagenet学习笔记 ImageNet(http://www.image-net.org)是李菲菲组的图像库,和WordNet 可以结合使用 (毕业于Caltec ...
- 【VS开发】【图像处理】相机中白平衡的算法模拟实现
相机主要技术点为3A算法. 而3A算法主要指的是自动对焦(AF).自动曝光(AE)及自动白平衡(AWB).自动白平衡:根据光源条件调整图片颜色的保真程度. 网上时常有类似招聘如下的招聘信息: ---- ...
- Oracle中的=:
dept_code=:dCode =:在这里的意思是变量绑定
- poj1011(DFS+剪枝)
题目链接:https://vjudge.net/problem/POJ-1011 题意:给定n(<=64)条木棍的长度(<=50),将这些木棍刚好拼成长度一样的若干条木棍,求拼出的可能的最 ...
- AKKA学习(二) 未完
Actor调用 从上面的例子中,我们可以大概的对AKKA在JAVA中的使用有一个全局的概念.这里我们在稍微细致的讲解一下. 在JAVA中使用AKKA进行开发主要有这几个步骤: 定义消息模型. 创建Ac ...
- 在linux下和Mac下如何实现快捷方式连接SSH远程服务器
其实特别简单 在本地命令执行目录/usr/local/bin 下新建一个shell脚本 比如 #vim ssh1 写入要执行的内容连接SSH #!/usr/bin/expect -f set user ...