Skip to content

vdom

一、 vdom 是什么?

从本质上来说,Virtual Dom 是一个 JavaScript 对象,通过对象的方式来表示 DOM 结构。

二、vdom 是用来做什么?

1、保证性能下限

  • 通过事务处理机制,将多次 DOM 修改的结果一次性的更新到页面上,从而有效的减少页面渲染的次数,减少修改 DOM 的重绘重排次数,提高渲染性能。

2、跨平台

  • Virtual DOM 本质上是 JavaScript 的对象,它可以很方便的跨平台操作,比如服务端渲染、uniapp 等;

三、ast 和 vdom 有什么关系?

这两者其实并没有什么关系,AST 仅在编译阶段存在,在项目运行时并没有 AST 的概念;而vdom 则是在渲染阶段生成的,主要用于比较渲染前后的数据结构变化。

AST 通常是在编译阶段出现的,例如在 Vue 文件中, 标签中的内容不仅包含了 HTML,还包含了一些自定义的 Vue 语法,如 v-if、v-for。这些语法既不属于 JavaScript 规范,也不是标准的 HTML 语法,常规的 JavaScript 引擎无法直接处理。因此,在将这些代码交给 JavaScript 引擎运行之前,需要先将其转换成标准的 JavaScript 语法结构,这就是 AST 的作用。Vue CLI 会将模板代码解析为 AST 结构,再转换为 JavaScript 代码,也就是我们常说的构建过程(build process)。

vdom 则是在运行时(Vue 运行时环境)出现的一种数据中间态。Vue 在每个渲染周期都会生成一个 vdom,如果每次渲染都使用 vdom 完全重新绘制整个 UI,页面就可能出现“闪屏”现象。为了避免这种情况,Vue 会在内部进行一次新旧 vdom 的 diff 操作,只提取发生变化的节点内容,然后仅渲染这些变化的部分,从而提高性能。因此,说 vdom 比真实 DOM 操作更快的说法并不准确,因为 vdom 最终仍需渲染成真实 DOM,区别在于这个过程的先后顺序和效率。

  1. 虚拟 dom 长啥样呢
html
<div class="demo">
  <span class="text">hello world</span>
</div>

vdom:

js
{
  tag: 'div'
  data: {
    class: 'demo'
  },
  children: [
    {
      tag: 'span',
      data: {
        class: 'text'
      }
      text: 'hello world'
    }
  ]
}

ast呢?

alt text

四、vdom diff

tips: diff算法就是比较两个对象的差异 vue2的dom diff: 我们拿到新旧节点的数组,然后初始化四个指针,分别指向新旧节点的开始位置和结束位置,进行两两对比,若是 新的开始节点和旧开始节点相同,则都向后面移动,若是结尾节点相匹配,则都前移指针。若是新开始节点和旧结尾节点匹配上了,则会将旧的结束节点移动到旧的开始节点前。若是旧开始节点和新的结束节点相匹配,则会将旧开始节点移动到旧结束节点的后面。若是上述节点都没配有匹配上,则会进行一个兜底逻辑的判断,判断开始节点是否在旧节点中,若是存在则复用,若是不存在则创建。最终跳出循环,进行裁剪或者新增,若是旧的开始节点小于旧的结束节点,则会删除之间的节点,反之则是新增新的开始节点到新的结束节点。