Vue.JS中虚拟DOM与Diff算法

129 阅读3分钟

一、虚拟DOM

1、为什么使用虚拟DOM

1)、直接操作DOM

  • 需要更新n个DOM节点,浏览器收到第一个DOM请求后并不知道还有几次更新操作,因此会马上执行流程,最终执行n次。第一次计算完,紧接着下一个DOM更新请求,前一次计算为无用功。每一次修改DOM都会影响性能。

2)、操作虚拟DOM

  • 虚拟DOM不会立即操作DOM,而是将这n次更新的diff内容保存到本地一个JS对象中,最终将这个JS对象一次性渲染到DOM树上,再进行后续操作,就只修改了一次DOM树,避免大量无谓的计算量。

2、虚拟dom的意义

  1. 虚拟DOM本质上是JavaScript对象,是对真实DOM的抽象,状态变更时,记录新树和旧树的差异最后把差异更新到真正的dom中。
  2. 虚拟DOM的作用:使用原生js或者jquery写页面的时候会发现操作DOM是一件非常麻烦的一件事情,往往是DOM标签和js逻辑同时写在js文件里,数据交互时不时还要写很多的input隐藏域,如果没有好的代码规范的话会显得代码非常冗余混乱,耦合性高并且难以维护。
  3. 另外一方面在浏览器里一遍又一遍的渲染DOM是非常非常消耗性能的,常常会出现页面卡死的情况;所以尽量减少对DOM的操作成为了优化前端性能的必要手段,vdom就是将DOM的对比放在了js层,通过对比不同之处来选择新渲染DOM节点,从而提高渲染效率。

二、Diff算法

1、Diff算法的作用

当DOM部分被修改时,只修改DOM改变的那部分,不会引起DOM树的重绘

2、Diff算法的实现原理

  • diff算法将虚拟DOM的某个节点数据改变后生成新的的node节点与旧节点进行比较,并替换为新的节点,具体过程就是调用Patch方法,比较新旧节点,一边比较一边给真实DOM打补丁进行替换

patch方法

  • patch接收两个参数oldVnode和Vnode分别代表上一个虚拟节点和Vue编译生成的虚拟节点,判断两节点是否值得比较,
  1. 值得比较则执行patchVnode
  • 找到对应的真实DOM
  • 判断Vnode和oldVnode是否指向同一个对象,如果是,那么直接return
  • 如果他们都有文本节点并且不相等,那么将真实DOM的文本节点设置为Vnode的文本节点。
  • 如果oldVnode有子节点而Vnode没有,则删除真实DOM的子节点
  • 如果oldVnode没有子节点而Vnode有,则将Vnode的子节点真实化之后添加到真实DOM
  • 如果两者都有子节点,则执行updateChildren函数比较子节点
  • 就这样一层一层比较下去
  1. 不值得比较则用Vnode替换oldVnode。如果两个节点都是一样的,那么就深入检查他们的子节点。如果两个节点不一样那就说明Vnode完全被改变了,就可以直接替换oldVnode。