虚拟 DOM 和 DOM diff

188 阅读3分钟

虚拟DOM

虚拟DOM是一棵以 JavaScript 对象 (VNode 节点) 作为基础的树,用对象属性来描述节点,实际上它只是一层对真实 DOM 的抽象。通过一系列操作使这棵树映射到真实环境上。

Virtual DOM 对象的节点跟 DOM Tree 每个位置的属性一一对应的,因为人们创造出虚拟 DOM 就是为了更好地将虚拟节点渲染到视图上,也就是把虚拟DOM变成真实的 DOM 节点,提高视图的渲染性能。

虚拟DOM的优点

  • 减少不必要的dom操作。 假如在一个ul里包含1000个li标签,改变其中几个li标签触发视图渲染,如果没有虚拟DOM的情况下会把整个ul替换掉重新渲染,这样大大增加了不必要的操作。 虚拟DOM对象上的节点和DOM树上的节点一一对应,在渲染时会将虚拟DOM上的节点和上一次的虚拟节点进行对比,找出需要更新的部分只将它们进行重新渲染,从而减少不必要的DOM操作。

注意: 在js层面上,DOM 的操作并不慢。DOM 操作慢是在浏览器渲染的过程里,在浏览器中改变一行数据就要全部重新渲染。大多数情况下虚拟 DOM 比 DOM 快,是因为需要更新的 DOM 节点要比原生 DOM 操作更新的节点少,浏览器重绘的时间更短。而且虚拟 DOM 的优势不在于单次的操作,用对比的算法,它可以将多次操作合并成一次操作,在大量、频繁的数据更新下,能够对视图进行合理、高效的更新。

  • 跨平台 由于虚拟 DOM 是以 JavaScript 对象为基础的,它的本质就是一个 JavaScript 对象。并不依赖真实平台环境,所以使它具有了跨平台的能力。像小程序、IOS或者安卓应用等

虚拟DOM的缺点

  • 需要额外的创建函数来创建虚拟DOM,虽然通过JSX语法来简化成XML写法,但是严重依赖打包工具,要添加额外的构建过程。
  • 当数据规模较大时虚拟dom的稳定性是比不上原生dom

DOM diff

DOM diff 即比较两颗虚拟 DOM 树区别的算法。仅在两个树的同级的虚拟节点之间做比较,递归地进行比较,最终实现整个 DOM 树的更新。

DOM diff 在做比较时分为了三个层级

1,Tree Diff(层级比较)

  • 先进行树结构的层级比较,对同一个父节点下的所有子节点进行比较;
  • 接着看节点是什么类型的,是组件就做 Component Diff;
  • 如果节点是标签或者元素,就做 Element Diff;

2,Component Diff (组件比较)

  • 若组件类型相同,则继续按照层级比较其虚拟 DOM的结构;
  • 如果组件类型不同,则替换整个组件的所有内容

3,Element Diff (元素比较)

关于Key的问题

给元素添加 Key 值后,React/Vue 在做 Diff 的时候会进行差异化对比,即通过 key 发现新老集合中的节点都是相同的节点,因此无需进行节点删除和创建,只需要将老集合中节点的位置进行移动,更新为新集合中节点的位置。 如果不添加 key 值会造成整个集合的删除再新增,不会进行移动 DOM 操作。除此之外,不加 key 在更新数据时可能会出现bug