- 大家都知道操作
DOM是很慢的,为什么慢的原因以及在「浏览器渲染原理」章节中说过,这里就不再赘述了- 那么相较于DOM来说,操作JS对象会快很多,并且我们也可以通过JS来模拟DOM
const ul = {
tag: 'ul',
props: {
class: 'list'
},
children: {
tag: 'li',
children: '1'
}
}
上述代码对应的 DOM 就是
<ul class='list'>
<li>1</li>
</ul>
- 那么既然
DOM可以通过JS对象来模拟,反之也可以通过JS对象来渲染出对应的DOM。当然了,通过JS来模拟DOM并且渲染对应的DOM只是第一步,难点在于如何判断新旧两个JS对象的最小差异并且实现局部更新DOM
首先
DOM是一个多叉树的结构,如果需要完整的对比两颗树的差异,那么需要的时间复杂度会是O(n ^ 3),这个复杂度肯定是不能接受的。于是React团队优化了算法,实现了O(n)的复杂度来对比差异。 实现O(n)复杂度的关键就是只对比同层的节点,而不是跨层对比,这也是考虑到在实际业务中很少会去跨层的移动DOM元素。 所以判断差异的算法就分为了两步
- 首先从上至下,从左往右遍历对象,也就是树的深度遍历,这一步中会给每个节点添加索引,便于最后渲染差异
- 一旦节点有子元素,就去判断子元素是否有不同
在第一步算法中我们需要判断新旧节点的
tagName是否相同,如果不相同的话就代表节点被替换了。如果没有更改tagName的话,就需要判断是否有子元素,有的话就进行第二步算法。
在第二步算法中,我们需要判断原本的列表中是否有节点被移除,在新的列表中需要判断是否有新的节点加入,还需要判断节点是否有移动。
举个例子来说,假设页面中只有一个列表,我们对列表中的元素进行了变更
// 假设这里模拟一个 ul,其中包含了 5 个 li
[1, 2, 3, 4, 5]
// 这里替换上面的 li
[1, 2, 5, 4]
从上述例子中,我们一眼就可以看出先前的
ul中的第三个li被移除了,四五替换了位置。
那么在实际的算法中,我们如何去识别改动的是哪个节点呢?这就引入了
key这个属性,想必大家在Vue或者React的列表中都用过这个属性。这个属性是用来给每一个节点打标志的,用于判断是否是同一个节点。
- 当然在判断以上差异的过程中,我们还需要判断节点的属性是否有变化等等。
- 当我们判断出以上的差异后,就可以把这些差异记录下来。当对比完两棵树以后,就可以通过差异去局部更新
DOM,实现性能的最优化。
当然了
Virtual DOM提高性能是其中一个优势,其实最大的优势还是在于:
- 将
Virtual DOM作为一个兼容层,让我们还能对接非Web端的系统,实现跨端开发。 - 同样的,通过
Virtual DOM我们可以渲染到其他的平台,比如实现SSR、同构渲染等等。 - 实现组件的高度抽象化
Virtual DOM 是一种优化浏览器DOM操作的技术,通过对比新旧Virtual DOM树的差异实现局部更新,降低性能开销。Vue等框架使用Virtual DOM以O(n)复杂度找出最小差异,实现高效更新。此外,Virtual DOM作为兼容层支持跨端开发,如Web、同构渲染等,还促进组件的抽象化。

487

被折叠的 条评论
为什么被折叠?



