六、Diff
基本原理
非 Diff 状态:更新时,卸载所有旧的 vnode 然后在挂载新的 vnode,无法复用,性能消耗大
Diff:新旧 vnode 进行比对,只更新有变化的地方
对于新旧 vnode,有以下三种更新方式:
- 新旧 vnode 的 children 长度一致:遍历一个,然后与另一个进行比对
- children 长度不一致,变量长度最短的那一个,然后依次挂载/卸载多出来的部分
DOM 复用
这里使用了 key 来让新旧 vnode 进行比对,提升复用度
移动节点的完整执行流程:
- 取出新 vnode 中的任意一个节点,获取其 key
- 寻找旧 vnode 中是否有相同的 key
- 如果有相同的 key,比对新旧 vnode 发现有改动,则打补丁 patch
节点移动解析
新旧 vnode 的 key 不一致,此时就需要把新 vnode 的引用移动到旧 vnode 对应的位置上(即使 key 值相同),才能让真实 DOM 渲染在同一个位置上
通过移动,使得新 vnode 可以应用到真实 DOM
七、双端 Diff
双端原理
新旧 vnode 的前后端均有一个 key,所以共计 4 个 keys
每轮进行一次交叉比较,单次命中后(即新旧节点的 key 相同),命中的索引向内收缩一个单位,之后进入下一轮交叉比较
交叉比较:
- oldvnode 头部节点与 newvnode 头部节点比较
- oldvnode 尾部节点与 newvnode 尾部节点比较
- oldvnode 头部节点与 newvnode 尾部节点比较
- oldvnode 尾部节点与 newvnode 头部节点比较
篇幅过大,无法阐述,后续补充
非理想情况
所谓非理想情况,即一轮交叉比较过程内,没有一次命中 key
解决方法:拿新 vnode 的一组子节点的头部节点去旧 vnode 对应子节点内找到可复用的节点
八、快速 Diff 算法
前后缀处理
首先进行预处理
- 将两段文本进行全等比较,如果相同,直接就不需要后续的 diff 了
- 删去两段文本相同的前后缀
- 设新旧子节点的头部节点为 j=0,让 j++,直到遇到不同的节点,在此过程中对于相同 key 值的新旧子节点都需要执行打补丁 patch(此过程处理所有前置节点)
索引过程
- 设置新子节点尾部为 newend,旧子节点尾部为 oldend
- newend 与 oldend 同时递减,处理所有的后置节点
注重原理分析,后续补充!