对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 ...
随机推荐
- 关于FPS游戏的设计问题
第一个想到的问题: 首先以unity的FPSCharactorController为例,这里规定,相机的方向中心一定是瞄准的方向中心.设置身体的扭曲朝向相机方向,这样身体可以弯腰.你们看图中,我让玩家 ...
- CF The World Is Just a Programming Task (Easy Version)【分析·思维】
题目传送门 题意: 给定一个括号序列,随意交换两个位置的括号之后,问有多少个不同长度的圈.关于圈的定义大概就是:将括号序列的后$k$个数放到括号序列的最前面,就是长度为$k$的圈.(看了好久题意emm ...
- 【DSP开发】shared memory VS mailbox
Hello, Hi everyone, I have a simple question. Could anyone explain to me the difference between Mail ...
- 2019JAVA第六次实验报告
Java实验报告 班级 计科二班 学号 20188442 姓名 吴怡君 完成时间 2019.10.18 评分等级 实验四 类的继承 实验目的 理解异常的基本概念: 掌握异常处理方法及熟悉常见异常的捕获 ...
- JSR303 校验扩展(分组、按顺序校验)
1.在spring MVC 项目中使用JSR303 校验数据合法性,一般情况下使用方法为 (1)在接受数据的实体使用注解标添加校验规则 package com.hzsj.wechatdto; impo ...
- [转帖]X86_64平台上利用qemu安装aarch64架构的虚拟机
X86_64平台上利用qemu安装aarch64架构的虚拟机 https://blog.csdn.net/chenxiangneu/article/details/78955462 遇到原作者一样的问 ...
- Java设计给小学生的自动出题系统
系统要求: 1.自动出题,涉及加减乘除四则运算 2.运算为两位数之间 3.减法不能出现负数 4.乘法结果不超过100 5.除法必须整除 6.用户决定出题量 7.用户决定几道题一换行 8.题目不允许重复 ...
- linux命令 集合
ps:查看所有进程 // -e :显示所有进程:-f:代表全格式 ps -ef | grep python :查看后台运行的python程序,| 表示管道,grep表示筛选 & 符号:后台执行 ...
- php 图像处理 抠图,生成背景透明png 图片
*自定义一个图片等比缩放函数 *@param string $picname 被缩放图片名 *@param string $path 被缩放图片路径 *@param int $maxWidth 图片被 ...
- Vue源码解析:AST语法树转render函数
开始 今天要说的代码全在codegen文件夹中,在说实现原理前,还是先看个简单的例子! <div class="container"> <span>{{ms ...