Vue原理--虚拟DOM
为什么需要虚拟DOM?
如果对前端工作进行抽象的话,主要就是维护状态和更新视图,而更新视图和维护状态都需要DOM操作。其实近年来,前端的框架主要发展方向就是解放DOM操作的复杂性。
运行js的速度是很快的,大量的操作DOM就会很慢,时常在更新数据后会重新渲染页面,这样造成在没有改变数据的地方也重新渲染了DOM 节点,这样就造成了很大程度上的资源浪费。
在jQuery出现以前,我们直接操作DOM结构,这种方法复杂度高,兼容性也较差。有了jQuery强大的选择器以及高度封装的API,我们可以更方便的操作DOM,jQuery帮我们处理兼容性问题,同时也使DOM操作变得简单。
但是聪明的程序员不可能满足于此,各种MVVM框架应运而生,有angularJS、avalon、vue.js等,MVVM使用数据双向绑定,使得我们完全不需要操作DOM了,更新了状态,视图会自动更新。更新了视图数据状态也会自动更新,可以说MVVM使得前端的开发效率大幅提升。但是其大量的事件绑定使得其在复杂场景下的执行性能堪忧,有没有一种兼顾开发效率和执行效率的方案呢?由此引入Virtual DOM(虚拟DOM)。
利用在内存中生成与真实DOM与之对应的数据结构,这个在内存中生成的结构称之为虚拟DOM 。
当数据发生变化时,能够智能地计算出重新渲染组件的最小代价并应用到DOM操作上。
Virtual DOM 算法
所谓的 Virtual DOM 算法。包括几个步骤:
1.用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中;
2.当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异;
3.把2所记录的差异应用到步骤1所构建的真正的DOM树上,视图就更新了。
Virtual DOM 本质上就是在 JS 和 DOM 之间做了一个缓存。可以类比 CPU 和硬盘,既然硬盘这么慢,我们就在它们之间加个缓存。
既然 DOM 这么慢,我们就在它们 JS 和 DOM 之间加个缓存。CPU(JS)只操作内存(Virtual DOM),最后的时候再把变更写入硬盘(DOM)。

比较两棵虚拟DOM树的差异
比较两棵DOM树的差异是 Virtual DOM 算法最核心的部分,这也是所谓的 Virtual DOM 的 diff 算法。
两个树的完全的 diff 算法是一个时间复杂度为 O(n^3) 的问题。但是在前端当中,你很少会跨越层级地移动DOM元素。所以 Virtual DOM 只会对同一个层级的元素进行对比:

上面的div只会和同一层级的div对比,第二层级的只会跟第二层级对比。这样算法复杂度就可以达到 O(n)。
在实际的代码中,会对新旧两棵树进行一个深度优先的遍历,这样每个节点都会有一个唯一的标记,如下图所示:

Virtual DOM 算法实现
Virtual DOM 算法得实现主要是用三个函数:element,diff,patch。然后就可以实际的进行使用,如下面代码所示:
// 1. 构建虚拟DOM
var tree = el('div', {'id': 'container'}, [
el('h1', {style: 'color: blue'}, ['simple virtal dom']),
el('p', ['Hello, virtual-dom']),
el('ul', [el('li')])
]) // 2. 通过虚拟DOM构建真正的DOM
var root = tree.render()
document.body.appendChild(root) // 3. 生成新的虚拟DOM
var newTree = el('div', {'id': 'container'}, [
el('h1', {style: 'color: red'}, ['simple virtal dom']),
el('p', ['Hello, virtual-dom']),
el('ul', [el('li'), el('li')])
]) // 4. 比较两棵虚拟DOM树的不同
var patches = diff(tree, newTree) // 5. 在真正的DOM元素上应用变更
patch(root, patches)
diff算法
用 三大策略 将O(n^3)复杂度 转化为 O(n)复杂度
- 策略一(tree diff):
Web UI中DOM节点跨层级的移动操作特别少,可以忽略不计。
- 策略二(component diff):
拥有相同类的两个组件 生成相似的树形结构,
拥有不同类的两个组件 生成不同的树形结构。
- 策略三(element diff):
对于同一层级的一组子节点,通过唯一id区分。
tree diff
(1)通过updateDepth对Virtual DOM树进行层级控制。
(2)对树分层比较,两棵树只对同一层次节点进行比较。如果该节点不存在时,则该节点及其子节点会被完全删除,不会再进一步比较。
(3)只需遍历一次,就能完成整棵DOM树的比较。

diff只简单考虑同层级的节点位置变换,如果是跨层级的话,只有创建节点和删除节点的操作。

如上图所示,以A为根节点的整棵树会被重新创建,而不是移动,因此官方建议不要进行DOM节点跨层级操作,可以通过CSS隐藏、显示节点,而不是真正地移除、添加DOM节点。
Vue原理--虚拟DOM的更多相关文章
- vue之虚拟DOM、diff算法
一.真实DOM和其解析流程? 浏览器渲染引擎工作流程都差不多,大致分为5步,创建DOM树——创建StyleRules——创建Render树——布局Layout——绘制Painting 第一步,用HTM ...
- 最近发现了一篇讲解Vue的虚拟DOM,diff很棒的文章,特定记录转载一下
本文章是转载的,为了方便以后复习,特地记录一下.他人请去原地址观看!!! 文章原地址:https://blog.csdn.net/m6i37jk/article/details/78140159 作者 ...
- Vue之虚拟DOM
一.真实DOM和其解析流程? 浏览器渲染引擎工作流程都差不多,大致分为5步,创建DOM树——创建StyleRules——创建Render树——布局Layout——绘制Painting 第一步,用HTM ...
- vue 的虚拟 DOM 有什么好处?
vue 中的虚拟DOM有什么好处?快! 首先了解浏览器显示网页经历的5个过程 1.解析标签,生成元素树(DOM树) 2.解析样式,生成样式树 3.生成元素与样式的关系 4.生成元素的显示坐标 5.显示 ...
- vue核心---虚拟dom的实现
生成dom的过程 由vue模板生成虚拟dom 虚拟dom转换成真实dom渲染到html页面 代码实现 要实现的真实dom <div id="box"> <p cl ...
- 从虚拟dom了解vue渲染函数
vue渲染函数就是render函数,他会返回一个VNode,VNode是一个js对象,是dom的映射 vue在介绍渲染函数那个章节看的不是很懂,所以想要彻底的理解渲染函数,首先需要了解vue的虚拟do ...
- vue虚拟dom和diff算法
vue的虚拟dom和diff算法 1.虚拟dom 虚拟dom,我的理解就是通过js对象的方式来具体化每一个节点,把dom树上面的每个节点都变为对象里的一个元素,元素的子元素变为子节点,节点上面的cla ...
- 解密虚拟 DOM——snabbdom 核心源码解读
本文源码地址:https://github.com/zhongdeming428/snabbdom 对很多人而言,虚拟 DOM 都是一个很高大上而且远不可及的专有名词,以前我也这么认为,后来在学习 V ...
- 虚拟Dom详解 - (一)
随着Vue和React的风声水起,伴随着诸多框架的成长,虚拟DOM渐渐成了我们经常议论和讨论的话题.什么是虚拟DOM,虚拟DOM是如何渲染的,那么Vue的虚拟Dom和React的虚拟DOM到底有什么区 ...
随机推荐
- 洛谷1196【NOI2002】题解
题目描述 公元五八○一年,地球居民迁至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米利恩星域爆发战争.泰山压顶 ...
- 正则表达式,grep,sed,
答案详见:http://www.cnblogs.com/linhaifeng/p/6596660.html 作业一:整理正则表达式博客 ^ # 行首定位 $ # 行尾定位 . # 匹配除换行符以外的任 ...
- 使用后台的limit 控制每页的容量
和上一个不使用limit的不同,如果不使用后台的限制,那么就必须自己定义一个计算属性,并且v-for这个计算的数组,而如果要用到后台的限制,那么就不需要自己计算,v-for的直接就是后台获取的数组 1 ...
- PC/FORTH 下的多任务使用
body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...
- 关于html的基础标签
html: 超文本标记语言 h1 -- h6: 标题标签 一级标题,一个页面中只能存在一个h1 数字越大,标题的级别越小br:换行p:段落 自带换行,前后自带间隙a::::href属性---指定将要跳 ...
- 机器学习 xgboost 笔记
一.数据预处理.特征工程 类别变量 labelencoder就够了,使用onehotencoder反而会降低性能.其他处理方式还有均值编码(对于存在大量分类的特征,通过监督学习,生成数值变量).转换处 ...
- LeakCanary 来检查 Android 内存泄漏
LeakCanary 来检查 Android 内存泄漏
- Windows创建Sciter的第一个程序.HelloWorld
介绍什么的就免了.直接进入正题 平台: Windows 10 IDE : Visual studio 2017 首先从官网下载最新的SDK,https://sciter.com/download/ 创 ...
- 提升算法——Adaboost
思路:通过改变训练样本权重,学习多个分类器,并将这些分类器进行线性组合,提高分类器性能.大多数提升方法都是改变训练数据的概率分布(数据的权值) 强可学习:存在一个多项式的学习算法能够学习他,并且正确率 ...
- 详解angular2组件中的变化检测机制(对比angular1的脏检测)
组件和变化检测器 如你所知,Angular 2 应用程序是一颗组件树,而每个组件都有自己的变化检测器,这意味着应用程序也是一颗变化检测器树.顺便说一句,你可能会想.是由谁来生成变化检测器?这是个好问题 ...