Skip to content

Diff 算法的文字性解释(vue 里其他算法性的也往这里放)

v-dom 虚拟 DOM 和 diff 算法

  • v-dom 虚拟 DOM
  • 通过 js 生成一个 ast 节点树/用对象模仿 dom 属性
  • dom 是内容很重的数据,操作起来容易浪费性能

diff 算法

无 key 算法

  • patchUnkeyedChildren 函数
    • 其中有 c1 旧的 v-node 和 c2 新的 v-node 两个参数
  • 第一步 遍历两个数组,新旧对比并且让新替换旧
  • 第二步 发现多的节点就新增
  • 第三步 发现少了就删除

有 key 算法,最长递增子序列

  • patchKeyedChildren 函数
    • 一样有 c1 和 c2 两个旧新节点数组
  • 第一步 前序算法/先从头比较两个节点数组
    • 比较使用 isSameVNodeType 函数,主要是比较 type(是不是 div 这种)和 key,都一样才返回 true
    • 第二步 比较中出现不同时则跳出,进行尾序对比,从后比较两个节点数组
    • 第三步 又发现不同的新节点则新增
    • 第四步 发现少了相同节点旧删除/卸载
    • 第五步 乱序时,比如新增删除位移同时发生,比如 input 框
  • 第一步 构建新节点的映射关系
    • key 是 12345,索引就是 01234,排序后 key 是 54321, 索引其实也不变, 实际上形成 key 和索引之间的 map 关系
  • 第二步 新节点 在旧节点中位置 的一个数组, 有多余就删掉,不包含旧节点也删掉
    • 如果节点交叉,就要用最长递增子序列做 move 是否 true 的判断
  • 第三步 开始最长递增子序列的对比
    • 首先进行一个贪心加二分查找结合的算法来求最长递增子序列
    • 如果在子序列中就要移动节点
    • 不在就跳过

vue2 的双端 diff

  • 先两两从头对比
  • 再两两从尾部对比
  • 接着两两头对比尾
  • 最后两两尾对比头

nextTick

  • 将回调推迟到下一个 dom 更新周期后执行。
  • 更改一些数据来等 dom 更新后马上使用
    • 一个例子是每次给某个元素中加上 n 行文字,然后求此时元素高度
    • 一般情况下需要 updated 钩子才能获取这个内容,一般脚本只能获取当前(未更新)的内容
    • 但 update 钩子会在所有更新操作都触发,所以很多余
  • nexttick 函数提供了很好的专门工具,在 dom 正式更新之后拿到数据
    • 相当于 nexttick 把操作加入到微任务队列最后
  • watch 这些也是用 nexttick 实现,比如一个循环加 1 一百次的函数,watch 或者 nexttick 最后都只会得到一个更新