前言

相信大家都在v-for中使用过key,脑海中也大概有印象,这个key写在这是为了提升性能的,但是再深一步问,这个key怎么就能优化性能呢?

所以这就是今天的题需要探讨的点

key的作用

在Vue.js官方文档中已经给出了key的作用

key这个特殊的属性,主要用于Vue的虚拟dom算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。

这是官方文档里的描述,但是这个回答太过于官方了,所以咱从源码角度去看key的作用

Vue项目为什么要使用nginx vue为什么要使用key_key

从diff去探讨key

在Vue中是采用diff算法进行的新旧虚拟节点对比,从而更新节点。

而在Vue的diff中,首先会进行4次猜测,其实是对新旧虚拟节点的头尾这4个进行交叉对比,在源码中如下图

Vue项目为什么要使用nginx vue为什么要使用key_key_02

好家伙,if else的神!

Vue项目为什么要使用nginx vue为什么要使用key_diff_03

这四种猜测,这里先不提,之后源码系列会慢慢讲patch这部分的逻辑

只要知道,在这四种猜测都不成功时,Vue会进入到一个判断,如下图

Vue项目为什么要使用nginx vue为什么要使用key_算法_04

这里就是对key的判断

如果有key属性,那么就会执行oldkeyToIdx[newStartVnode.key],而这个oldkeyToIdx是个对象,内部进行了如下图的操作,其实就是将key绑定在对象的映射中,然后直接使用olkeyToIdx[key]的映射找到相应的旧虚拟节点,这个函数如下图

Vue项目为什么要使用nginx vue为什么要使用key_key_05

如果没有key属性,则是使用findIdxInold这个函数,而这个函数内部就是一个for循环遍历,找相同节点,如图

Vue项目为什么要使用nginx vue为什么要使用key_算法_06

相比而言,对象的映射速度会比for循环遍历要快

Vue项目为什么要使用nginx vue为什么要使用key_算法_07

误区

这时有人会说,我不用key的情况下,diff可能会更快啊,比如在遍历简单模板的情况下,会导致虚拟新旧节点对比更快,节点也会复用。

这个观点是没错的,但是偏题了,这题目问的是key的作用,那么让我们看看官方文档怎么说的

Vue项目为什么要使用nginx vue为什么要使用key_diff_08

可以看到,提出的遍历简单模板的情况是在Vue文档中所说的默认模式。但这模式虽然是高效的,但是只适用于不依赖子组件状态或临时DOM状态(例如: 表单输入值)的列表渲染输出

所以key的作用是为了快速找到相对应的虚拟节点,而这上面的所说的默认模式,并不是key的作用

总结

总结一下:

key是给每一个vnode的唯一id,可以依靠key,更准确, 更快的拿到oldVnode中对应的vnode节点。

  • 更准确: 因为带key就不是就地复用了,在sameVnode函数中 a.key === b.key对比中可以避免就地复用的情况。所以会更加准确。

Vue项目为什么要使用nginx vue为什么要使用key_Vue项目为什么要使用nginx_09

  • 更快: 利用key的唯一性生成map对象并通过映射来获取对应节点,比遍历方式更快。

想说的话

发现面试题不能光看光记,得去理解了,再总结

所以也就诞生了这个每日一题系列,我将在之后准备春招的日子里,每天一篇面试题的解析,这样就不是死记硬背的面试题了,而是掺杂着自己的理解在内

加油!

Vue项目为什么要使用nginx vue为什么要使用key_key_10