对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 ...
随机推荐
- C#学习笔记一(概念,对象与类型,继承)
一.基础 1.CLR为公共语言运行库,类似于JVM 2..NET Framwork是一个独立发布的程序包,其包含了CLR,类库及相关的语言编辑器等工具,类似于JDK,除了C#,还有其他几种语言在CLR ...
- linux scp放后台执行方法
客户要搭建异地的容灾dg,压缩备份集500G,只能使用scp,前台跑经常超时,使scp放后台跑完成相关的文件传输: FULLBAK_LFCXJMYB_20190507_6448_1.DBFILE 10 ...
- word2vec原理浅析
1.word2vec简介 word2vec,即词向量,就是一个词用一个向量来表示.是2013年Google提出的.word2vec工具主要包含两个模型:跳字模型(skip-gram)和连续词袋模型( ...
- Robots协议一定放在网站根目录下
一.网络爬虫的尺寸 1.以爬取网页,玩转网页为目的进行小规模,数据量小对爬取速度不敏感的可以使用request库实现功能(占90%) 2.以爬取网站或爬取系列网站为目的,比如说获取一个或多个旅游网站的 ...
- Python示例-TCP Port Scan
import socket import threading # target host address host = "127.0.0.1" # thread list thre ...
- GITFLOW流程
GITFLOW流程规范 GIT的使用非常的灵活,但是灵活就导致在使用的过程中有各种各样的情况,根据现有项目组的情况,使用GITFLOW流程规范作为项目开发流程规范. 该规范参考地址: 深入理解学习Gi ...
- Java作业 题目:16版.情人节送玫瑰花
题目:16版.情人节送玫瑰花 题干: 1.实验要求 本实验要求:以情人节送花为业务背景,体验自定义异常以及异常处理机制. 1-1. 业务说明: 1-1.1. 本实验以情人节送花为业务背景,女方提出送花 ...
- Codeforces893F_Subtree Minimum Query
题意 给定一棵树和根,每个点有点权,强制在线询问\(x\)子树里离\(x\)距离不超过\(k\)的最小点权. 分析 权值线段树合并的套路题,dfs,以深度作为下标,点权作为值,对每个点建立一颗权值线段 ...
- Labeling Balls POJ - 3687 优先队列 + 反向拓扑
优先队列 + 反向拓扑 //#include<bits/stdc++.h> #include<iostream> #include<cstdio> #include ...
- 关于hstack和Svstack
关于hstack和Svstack import numpy as np>>> a = np.array((1,2,3))>>> aarray([1, 2, 3])& ...