vue-diff算法之原理——中

62 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情

vue-diff算法之原理——上

节点列表末尾尝试复用

上次说到了老节点和新节点开头尽量复用,接下来就是后面尽量复用了,尝试比对新节点最后一个和老节点最后一个type和key是否相同,如果是直接调用patch方法更新dom,这个节点的更新也就完毕了,后面就不用处理了,然后将新老节点结束索引往前移动一位,再尝试前面的操作,直到遇到不可以复用的老节点后,结束这个尝试,最坏的结果是一个都不可以复用,但这无关紧要。

  while (i <= e1 && i <= e2) {
    const n1 = c1[e1];
    const n2 = c2[e2];
    if (isSameVNodeType(n1, n2)) {
      patch(n1.key);
    } else {
      break;
    }
    e1--;
    e2--;
  }

阶段性成果

通过尝试复用列表开始和尝试复用列表结束,已经将开始可以复用节点处理完,结束可以复用的dom处理完了 假设有如下新的和旧的节点列表

image.png 肉眼可见的,前面两个key为a,b的节点,和后面两个key为f,g的节点都是可以复用的,只需要patch一下就完成了dom更新,而到现在为止。我们的代码,已经可以做到这一点了。

image.png 后面还未处理的就剩下如下这些不是开头可以复用结尾可以复用,不太规律的节点了

image.png 当前这只是通过人来判断的,后面要用逻辑处理

老节点能用的都用了,新节点还没处理完

i是新老节点列表当前未处理的开始位置索引,e1是老节点当前未处理的结束位置的索引,当开始位置大于结束位置,则说明,需要处理的节点已经没有了。此时逻辑就非常简单,直接mountElement所有剩下未处理的新节点。

  if (i > e1) {
    while (i <= e2) {
      const n2 = c2[i];
      mountElement(n2.key);
      i++;
    }
  }

假设新旧节点结构如下

let list1 = [{
    key: "a",
  },
  {
    key: "b",
  },
  {
    key: "f",
  },
  {
    key: "g",
  },
];
let list2 = [{
    key: "a",
  },
  {
    key: "b",
  },
  {
    key: "e",
  },
  {
    key: "c",
  },
  {
    key: "d",
  },
  {
    key: "h",
  },
  {
    key: "f",
  },
  {
    key: "g",
  },
];

前面尝试复用结束后i变成2,后面尝试复用结束后e1变成1。此时就符合老节点已经处理完,只剩下新节点,e2此时为5,新节点未处理的节点分别为e,c,d,h,也就是下标2,3,4,5。

image.png

新节点处理完了,老节点没处理完

上面的情况反过来,新节点处理完了。老节点没处理完,这些老节点就全部卸载就行了。

  else if (i > e2) {
    while (i <= e1) {
      const n1 = c1[i];
      unmount(n1.key);
      i++;
    }
  } 

最后一种剩下了新的和老的,是diff算法最核心的算法了,也是最终要面对的问题,今天脑子不够用了,要等明天来搞了