双端比较的原理

首先说一下为什么要双端比较,这是由于之前的单端比较是有不必要的损耗的。

Untitled

上图的单端比较重,我们会移动两次DOM节点,但是看了新老节点的示意图我们就一目了然的知道,最简单的办法是将p-3对应的元素移动到最后面即可,只需要一次操作。

双端Diff就能解决这个问题。

双端比较的方式

Untitled

如上图,我们会有四个索引。分别指向新节点的开始节点,结束节点,以及旧节点的开始节点和结束节点。

每一轮Diff,我们都会重复下面四步比较:

  1. 旧节点的开始节点,与新节点的开始节点是否相同。如果相同,则更新节点内容(因为此时顺序正确不需要调整),并且更新newStartIdxoldStartIdx索引,指向下一个新旧节点。开始下一轮循环
  2. 旧节点的结束节点,与新节点的结束节点是否相同,如果相同,则更新节点内容,并更新索引,开始下一轮循环。
  3. 旧节点的开始节点,与新节点的结束节点是否相同,如果相同,则将旧节点的开始节点对应的真实DOM移动到旧节点的最后面(oldEndIndex指向的真实节点的后面)。并开始下一轮循环。
  4. 旧节点的结束节点,与新节点的开始节点是否相同,如果相同,则更新旧节点的结束节点的真实DOM移动到旧节点的开始节点之前。并开始下一轮循环。

以上四步,只要符合一步,则更新真实节点的内容,并且移动真实节点。移动后修改对应索引值,并再次重新开始对比。

Untitled

双端比较的优势

还是一开始的例子,双端比较比单端比较在大部分情况下所做的操作更少。

只做一次DOM移动操作

只做一次DOM移动操作

非理想状况的比较

上面的例子中,我们默认了只要比较了新旧列表的四个角即可命中一个,但是如果没有命中应该怎么操作呢?如下图所示的数据结构则无法命中。