核心原理&源码
Diff 算法
这里参考大佬文章:https://mp.weixin.qq.com/s/oAlVmZ4Hbt2VhOwFEkNEhw
diff 算法的进化
关于 diff 算法的最经典的就是 Matt Esch 的 virtual-dom,以及 snabbdom(被整合进 vue 2.0中)。
最开始出现的是 virtual-dom 这个库,是大家好奇 React 为什么这么快而搞鼓出来的。它的实现是非常学院风格,通过深度优先搜索与 in-order tree 来实现高效的 diff 。
然后是 cito.js 的横空出世,它对今后所有虚拟 DOM 的算法都有重大影响。它采用两端同时进行比较的算法,将 diff 速度拉高到几个层次。
紧随其后的是 kivi.js,在 cito.js 的基出提出两项优化方案,使用 key 实现移动追踪以及及基于 key 的最长自增子序列算法应用(算法复杂度 为O(n^2))。
但这样的 diff 算法太过复杂了,于是后来者 snabbdom 将 kivi.js 进行简化,去掉编辑长度矩离算法,调整两端比较算法。速度略有损失,但可读性大大提高。再之后,就是著名的vue2.0 把sanbbdom整个库整合掉了。
下面我们就来讲讲这几个虚拟 DOM 库 diff 算法的具体实现:
virtual-dom
virtual-dom 作为虚拟 DOM 开天辟地的作品,采用了对 DOM 树进行了深度优先的遍历的方法。
体现到代码上:(可以看成伪代码)
VDOM 节点的对比
上面代码只是对 VDOM 进行了简单的深度优先遍历,在遍历中,还需要对每个 VDOM 进行一些对比,具体分为以下几种情况:
- 旧节点不存在,插入新节点;新节点不存在,删除旧节点
- 新旧节点如果都是 VNode,且新旧节点 tag 相同
- 对比新旧节点的属性
- 对比新旧节点的子节点差异,通过 key 值进行重排序,key 值相同节点继续向下遍历
- 新旧节点如果都是 VText,判断两者文本是否发生变化
- 其他情况直接用新节点替代旧节点
详细代码加详细注释
属性的对比
子节点的对比
这一部分可以说是 diff 算法中,变动最多的部分,因为前面的部分,各个库对比的方向基本一致,而关于子节点的对比,各个仓库都在前者基础上不断得进行改进。
首先需要明白,为什么需要改进子节点的对比方式。如果我们直接按照深度优先遍历的方式,一个个去对比子节点,子节点的顺序发生改变,那么就会导致 diff 算法认为所有子节点都需要进行 replace,重新将所有子节点的虚拟 DOM 转换成真实 DOM,这种操作是十分消耗性能的。
但是,如果我们能够找到新旧虚拟 DOM 对应的位置,然后进行移动,那么就能够尽量减少 DOM 的操作。
virtual-dom 在一开始就进行了这方面的尝试,对子节点添加 key 值,通过 key 值的对比,来判断子节点是否进行了移动。通过 key 值对比子节点是否移动的模式,被各个库沿用,这也就是为什么主流的视图库中,子节点如果缺失 key 值,会有 warning 的原因。
具体是怎么对比的,我们先看代码:
这里首先需要对新的子节点进行重排序,先进行相同节点的 diff ,最后把子节点按照新的子节点顺序重新排列。
这里有个较复杂的部分,就是对子节点的重新排序。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.e1idc.net