一直都想写点东西,但是也许可能是因为懒惰,也许是文笔太烂,每当要提笔写的时候,总会有无从下手的感觉。想当年,本人也是很喜欢的写作的,不说奋笔疾书,起码不会无从下手;然则,如今写一个字都是难的。可能是因为步入社会后,整个人变得越来越浮躁,一浮躁就无法静下来来沉淀自己,无法思考,故而书写能力甚至表达能力也越来越退化了......每思于此,痛彻心扉...... 闲话不说,步入正题。
心血来潮,了解了下vue中的diff算法......
从源码来看,vue在update的时候会调用如下函数:
而其中的vm._patch_才是进行vnode diff的核心,上面那个初始化render,后面这个是updates。
接下里进入方法内部:
核心是这段代码,能优化的地方就是在sameVnode(oldVnode, vnode)===true时。
里面核心
1.显示抽离modules中的update或者hook中的update,进行操作,主要是更新vnode中的attrs,class,dom-props,events,style,directives,refs...
2.如果vnode不是文本vnode,若oldVnode,和vnode都存在children的话,直接updateChildren;
若vnode children存在且oldVnode children不存在的话,则addVnodes添加整个vnode children对应的新节点;若vnode children不存在且oldVnode children存在的话,则删除oldVnode children对应的旧节点;若vnode是文本,则如果vnode不是文本节点或者是文本节点但是text值不相等的时候,直接设置新节点的文本值;
3.updateChildren是如何update的呢,
如源码所示,新旧节点序列(兄弟节点)的头和尾都定义了两个指标,目的是用来遍历,那么如何遍历呢?首先这四个节点必须存在,否则往后或者往前移动一位;然后oldVnode和新的vnode的头尾两个vnode两两进行比较,如果是sameNode则进行相应的dom节点移动或者不移动,然后就是比较其子节点重复步骤二,指标移动;再然后就是先抽取出oldVnode序列的带有key的节点放在map中,然后再遍历新的vnode序列,判断该vnode的key是否在map中若在则找到该key对应的oldVnode,如果此oldVnode与遍历到的vnode 是sameVnode的话则复用dom并移动dom节点位置,并重复步骤二,否则就是重新创建新的dom节点,指标移动。
综上:描述的马马虎虎,也不知道看客们能否明白我的表达.....哎,再次证明表达能力确实不行......
个人观点,欢迎吐槽求踩:
光从diff来看的话,这个key的作用并不是很大,判断复用dom节点的标准是sameVnode函数,并不能光凭key值进行判断...从官方文档上说,key的作用很大,甚至在!production的时候会有warn出现,那肯定key在其他使用场景中发挥着更大的作用,可供后续研究......