阅读 332

虚拟DOM和DOM diff

一、虚拟 DOM 是什么

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

在 JavaScript 里面,虚拟 DOM 表现为一个 Object 对象。并且最少包含标签名 (tag)、属性 (attrs) 和子元素对象 (children) 三个属性。不同的框架对这三个属性的名命可能会有差别。

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

二、虚拟 DOM 的优点

1. 减少 DOM 操作

  • 虚拟DOM可以将多次操作合并为一次操作,减少DOM操作的次数。比如你添加1000个节点,DOM要添加1000次,虚拟DOM只需要一次
  • 虚拟DOM借助DOM diff可以把多余的操作省掉,减少DOM操作的范围。比如你添加1000个节点,其实只有10个是新增的。

2. 跨平台

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

三、虚拟 DOM 的缺点

需要额外的创建函数,如create Element或h,但是可以通过JSX来简化成XML写法。

四、DOM diff 是什么

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

1. diff 算法主要包括几个步骤:

  • 用 JS 对象的方式来表示 DOM 树的结构,然后根据这个对象构建出真实的 DOM 树,插到文档中。
  • 当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树的差异
  • 最后把所记录的差异应用到所构建的真正的DOM树上,视图更新。

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

Tree Diff(层级比较)

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

Component Diff (组件比较)

若组件类型相同,则继续按照层级比较其虚拟 DOM的结构;

如果组件类型不同,则替换整个组件的所有内容。

Element Diff (元素比较)

如果节点是原生标签,则看标签名做比较是否相同来决定替换还是更新属性 然后进入标签后代递归 Tree Diff。

五、DOM diff 的优点

DOM diff算法可以排除多余的DOM操作。DOM diff会对比前后两次DOM树的区别,然后只更新有变化的DOM节点,优化操作。

六、DOM diff 的问题(key)

同级比较会出现bug。 diff算法是从左往右进行同层级对比的,如果发现元素相同但是内容不相同,会直接修改内容。这会导致有时删除了一个节点,结果却是另外一个节点被删除了。

这个问题可以通过给每一个列表指定key值来解决,给元素加了 Key 值之后,React/Vue 在做 Diff 的时候会进行差异化对比,即通过 key 发现新老集合中的节点都是相同的节点,因此无需进行节点删除和创建,只需要将老集合中节点的位置进行移动,更新为新集合中节点的位置。 不添加 key 值会造成整个集合的删除再新增,不会进行移动 DOM 操作。

要注意的是,index 不应该作为循环的key。

文章分类
前端
文章标签