首先要明确的一点是:DOM操作慢是对比JS原生API,如数组操作。任何基于DOM的库(Vue,React)都不可能在操作DOM时比DOM快。DOM操作不算太慢,慢的是浏览器渲染时间,而浏览器在渲染时是无法交互的。

但在某些情况下,虚拟DOM会比真实DOM快。规模较小时,虚拟DOM比DOM快,担当规模达到一定程度时,DOM可能比虚拟DOM快。

虚拟DOM的优点

减少DOM操作

即减少DOM操作次数。虚拟DOM可以将多次操作合并为一次操作。

举个例子,比如说要添加1000个节点,真实DOM是一个接一个添加的,而虚拟DOM是一次性添加1000个节点。

还是这个例子,如果你要在已经添加完1000个节点的页面上再新增10个节点,真实DOM可能无法区分,只能重新渲染1010个节点。而虚拟DOM可以通过DOM diff对比前后区别只重新渲染10个新增节点。

跨平台

虚拟DOM不仅可以变成DOM,还可以变成小程序、IOS应用、安卓应用,因为虚拟DOM本质上只是一个JS对象。

虚拟DOM是什么

一个能代表DOM树的对象,通常含有标签名标签上的属性事件监听和子元素们,以及其他属性。

虚拟DOM的缺点

需要额外的创建函数,如createElement(React)或h(Vue),但可以通过JSX语法简化XML写法。但这样严重依赖打包工具,否则浏览器不认识,更无法运行。

DOM diff

DOM diff是虚拟DOM的对比算法。就是一个函数,用于对比上下两次DOM树的区别,获得需要运行的DOM操作。

DOM diff的运行逻辑

Tree diff

  • 将新旧两颗DOM树进行对比,找出哪些节点需要更新
  • 如果节点是组件就看Component diff
  • 如果是标签更新就看Element diff

Component diff

  • 如果节点是组件,就先看组件
  • 类型不同就直接替换(删除旧的)
  • 类型相同则只更新属性
  • 然后深入组件做Tree diff(递归)

Element diff

  • 如果节点是原生标签,则看标签名
  • 标签名不同直接替换,相同则值更新属性
  • 然后进入标签后代做Tree diff(递归)

DOM diff的问题

同级比较存在BUG,需要添加key来做标记。

出现的问题可以参考文章Vue2.0 v-for 中 :key 到底有什么用?