前端面试系列【007】 – 你知道 vue 中 key 的作用和工作作原理吗?说说你对它的理解

时间:2020-9-8 作者:admin

本文仅针对 vue 2.6.x。

对于这个问题,如果看过下面这篇文章,应该会非常清楚:

四:diff 算法

本文就从作用到原理的角度来回答上面提出的问题。

解析

key 在 vue 中,除了解决 list 渲染过程中一些隐蔽的 bug,提高渲染效率,以及在过渡过程中区分节点以外,最主要的用途还是在 diff 算法中

首先要知道 vue 的更新流程:

reactiveSetter → dep.notify()→ watcher.update() → queueWatcher() → watcher.run() → updateComponent() → vm._render() → vm._update() → vm.patch() → patch()

而 key 起作用的位置则在 patch()中。

要回答这个问题,除了要知道更新流程以外,还要知道 vue 的 diff 算法:首尾假猜策略。由于上文已经详细描述过了,这里就不再赘述。

在 diff 的过程中,首先需要判断两个节点是否是相同类型的节点,用到的方法如下:

function sameVnode(a, b) {
  return (
    a.key === b.key &&
    ((a.tag === b.tag &&
      a.isComment === b.isComment &&
      isDef(a.data) === isDef(b.data) &&
      sameInputType(a, b)) ||
      (isTrue(a.isAsyncPlaceholder) &&
        a.asyncFactory === b.asyncFactory &&
        isUndef(b.asyncFactory.error)))
  );
}

可以看到,最首先比较的是二者的 key。

如果没有设置 key,则 key 为 undefine,而我们知道,在 js 中,undefine === undefine 返回是 true。

后面比较的东西是标签,是否为注释,是否定义了 data 等等,由于绝大部分的修改动作都是由修改数据触发,所以多数情况下,key 相同,则 sameVnode 就会判断两个节点是相同节点。

那么,这会造成什么影响呢?

举个例子来看看吧!

<div id="demo">
  <h1>虚拟DOM</h1>
  <div>
    <p v-for="a in arr" :key="a">{{a}}</p>
    <button @click="handleClick">click</button>
  </div>
</div>
<script>
  const app = new Vue({
    el: "#demo",
    data: { arr: ["A", "B", "C", "D"] },
    methods: {
      handleClick() {
        this.arr.splice(1, 0, "E");
      },
    },
  });
</script>

对于上面的 demo,当点击按钮的时候,会在数组中 A 后插入一个元素 E,即新老数组分别为:

  • A, B, C, D
  • A, E, B, C, D

在设定了 key 的情况下(这里认为每个元素 key 不同),diff 流程如下:

  • Step 1:比较 A, A – 相同类型节点,直接 patch,由于数据没有改变,所以不发生 dom 结构变化
  • Step 2:比较 B, E – 不同类型节点,进入下一步判断
    • Step 2.2:比较 D, D – 相同类型节点,直接 patch,由于数据没有改变,所以不发生 dom 结构变化
  • Step 3:比较 B, E – 不同类型节点,进入下一步判断
    • Step 3.2:比较 C, C – 相同类型节点,直接 patch,由于数据没有改变,所以不发生 dom 结构变化
  • Step 4:比较 B, E – 不同类型节点,进入下一步判断
    • Step 4.2:比较 B, B – 相同类型节点,直接 patch,由于数据没有改变,所以不发生 dom 结构变化
  • Step 5:循环结束,将 E 插入,发生 dom 结构变化

综上:这里总共个发生了 1 次 dom 结构变化。

那么,在不设定 key 的情况下,diff 流程又将如何呢?

  • Step 1:比较 A, A – 相同类型节点,直接 patch,由于数据没有改变,所以不发生 dom 结构变化
  • Step 2:比较 B, E – 相同类型节点,直接 patch,由于数据发生改变,所以发生 dom 结构变化
  • Step 3:比较 C, B – 相同类型节点,直接 patch,由于数据发生改变,所以发生 dom 结构变化
  • Step 4:比较 D, C – 相同类型节点,直接 patch,由于数据发生改变,所以发生 dom 结构变化
  • Step 5:循环结束,将 D 插入,发生 dom 结构变化

综上:这里总共个发生了 4 次 dom 结构变化。

可以看到,二者的性能差距是极大的,而这也是 key 在 vue 中最大的作用。

结语

更佳阅读体验:007 – 你知道 vue 中 key 的作用和工作作原理吗?说说你对它的理解

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。