【Vue面试题】谈谈你对Vue的diff算法的理解

1
diff
算法到底是什么?

diff
算法是一种通过同层的 节点进行比较的高效算法,它可以不用频繁操作
DOM
,而是选用虚拟
DOM
节点操作,说人话就是专门用来处理虚拟DOM节点的。

2 操作流程?

为了更好理解

Vue
diff
算法,请先看一位B站大佬精心制作的

动画演示。

通过上面视频可以很好理解diff算法的比较流程,清楚在循环从左右两边向中间比较的更新、插入、删除、查询操作。

它的操作本质就是:
分别遍历新旧虚拟

DOM
节点的数组,接着通过循环左右双指针比较判断。

新的头 newStartIndex 和老的头 oldStartIndex 对比

新的尾 newEndIndex 和老的尾 oldEndIndex 对比

新的头 newStartIndex 和老的尾 oldEndIndex 对比

新的尾 newEndIndex 和老的头 oldStartIndex 对比

3 解析github源码

我看到掘金的一篇讲的很不错,可以看看,深入浅出虚拟 DOM 和 Diff 算法,及 Vue2 与 Vue3 中的区别,我就只负责总结一下学习笔记吧。

而且它讲的Vue3涉及到diff的内容也很易理解。

3.1 patch函数:对比新旧虚拟DOM

3.1.1 什么时候触发?

在页面 首次渲染 的时候会调用一次

patch
并创建新的
vnode
,不会进行更深层次的比较。

在组件中数据发生变化时:

  1. 先触发
    setter
    然后通过
    Notify
    通知
    Watcher
  2. 对应的
    Watcher
    会通知更新并执行更新函数,它会执行
    render
    函数获取新的虚拟
    DOM
  3. 执行
    patch
    对比上次渲染结果的老的虚拟
    DOM
    ,并计算出最小的变化,然后再去根据这个最小的变化去更新真实的
    DOM
    ,也就是视图
    View

3.1.2 patch的更新流程流程(源码第700行)

3.2 patchVnode函数:对比节点文本变化或子节点变化

  • 如果
    oldVnode
    vnode
    的引用地址是一样的,就表示节点没有变化,直接返回。
  • 通过
    oldVnode
    isAsyncPlaceholder
    判断注释、
    v-if
    和异步函数的情况,选择跳过异步组件的检查,直接返回。
  • 如果
    oldVnode
    vnode
    都是静态节点,有相同的
    key

    • vnode
      是克隆节点或者
      v-once
      指令控制的节点时
      • oldVnode.elm
        oldVnode.child
        都复制到
        vnode
        上,然后返回。
  • 如果
    vnode
    不是文本节点也不是注释的情况下:
    • 如果
      vnode
      文本为
      undefined
      ,就删掉
      vnode.elm
      文本
    • 如果
      vnode
      oldVnode
      都有子节点,而且子节点不一样的话,就调用
      updateChildren
      更新子节点
    • 如果只有
      vnode
      有子节点,就调用
      addVnodes
      创建子节点
    • 如果只有
      oldVnode
      有子节点,就调用
      removeVnodes
      删除该子节点
  • 如果
    vnode
    是文本节点但是和
    oldVnode
    文本内容不一样,就更新文本

3.3 updateChildren:对比子节点的函数

当每轮循环对比时都不能满足找到对应的key值与标签值一致的情况时,那么要不断拿 新的开始节点 的 key 去 老的 开始节点的子节点 children 找。

  • 如果没找到,就创建一个新的节点
  • 如果找到了,再对比标签是不是同一个节点
    • 如果是同一个节点,就调用 patchVnode 进行后续对比,然后把这个节点插入到 老的 开始节点 前面,并且移动新的开始下标,继续下一轮循环对比
    • 如果不是相同节点,就创建一个新的节点
  • 如果 老的 vnode 先遍历完,就添加 新的 vnode 没有遍历的节点
  • 如果 新的 vnode 先遍历完,就删除 老的 vnode 没有遍历的节点

标签: Javascript

添加新评论