Vuejs设计与实现6-Diff算法

六、Diff

基本原理

非 Diff 状态:更新时,卸载所有旧的 vnode 然后在挂载新的 vnode,无法复用,性能消耗大

Diff:新旧 vnode 进行比对,只更新有变化的地方

对于新旧 vnode,有以下三种更新方式:

  1. 新旧 vnode 的 children 长度一致:遍历一个,然后与另一个进行比对
  2. children 长度不一致,变量长度最短的那一个,然后依次挂载/卸载多出来的部分

DOM 复用

这里使用了 key 来让新旧 vnode 进行比对,提升复用度

移动节点的完整执行流程:

  1. 取出新 vnode 中的任意一个节点,获取其 key
  2. 寻找旧 vnode 中是否有相同的 key
  3. 如果有相同的 key,比对新旧 vnode 发现有改动,则打补丁 patch

节点移动解析

新旧 vnode 的 key 不一致,此时就需要把新 vnode 的引用移动到旧 vnode 对应的位置上(即使 key 值相同),才能让真实 DOM 渲染在同一个位置上

通过移动,使得新 vnode 可以应用到真实 DOM


七、双端 Diff

双端原理

新旧 vnode 的前后端均有一个 key,所以共计 4 个 keys

扫描二维码关注公众号,回复: 14567057 查看本文章

每轮进行一次交叉比较,单次命中后(即新旧节点的 key 相同),命中的索引向内收缩一个单位,之后进入下一轮交叉比较

交叉比较:

  1. oldvnode 头部节点与 newvnode 头部节点比较
  2. oldvnode 尾部节点与 newvnode 尾部节点比较
  3. oldvnode 头部节点与 newvnode 尾部节点比较
  4. oldvnode 尾部节点与 newvnode 头部节点比较

篇幅过大,无法阐述,后续补充


非理想情况

所谓非理想情况,即一轮交叉比较过程内,没有一次命中 key

解决方法:拿新 vnode 的一组子节点的头部节点去旧 vnode 对应子节点内找到可复用的节点


八、快速 Diff 算法

前后缀处理

首先进行预处理

  1. 将两段文本进行全等比较,如果相同,直接就不需要后续的 diff 了
  2. 删去两段文本相同的前后缀
  3. 设新旧子节点的头部节点为 j=0,让 j++,直到遇到不同的节点,在此过程中对于相同 key 值的新旧子节点都需要执行打补丁 patch(此过程处理所有前置节点)

索引过程

  1. 设置新子节点尾部为 newend,旧子节点尾部为 oldend
  2. newend 与 oldend 同时递减,处理所有的后置节点

注重原理分析,后续补充!


猜你喜欢

转载自blog.csdn.net/delete_you/article/details/128441722