Virtual Dom中的diff算法

296 阅读3分钟

虚拟Dom是由普通JS对象来描述DOM对象

  • 虚拟DOM可以维护程序的状态,跟踪上次的状态
  • 通过比较前后两次状态差异更新真实DOM

虚拟DOM的作用和虚拟库

作用:

  • 维护状态和视图的关系

  • 复杂视图情况下提升渲染性能

  • 跨平台

    • 浏览器平台渲染DOM
    • 服务端渲染SSR(Nuxt.js/Next.js)
    • 原生应用(Weex/ReactNative)
    • 小程序(mpvue/uniapp)

虚拟DOM中的diff算法

  • 查找两棵树每一个节点的差异

  • Snabbdom对diff算法进行优化

    • DOM操作的时候很少会跨级别操作节点

    • 只比较同级别的节点

    • 执行过程

      • oldStartVnode/newStartVnode(旧开始节点/新开始节点)
      • oldEndVnode/newEndVnode(旧结束节点/新结束节点)
      • oldStartVnode/newEndVnode(旧开始节点/新结束节点)
      • oldEndVnode/newStartVnode(旧结束节点/新开始节点)

旧开始节点/新开始节点如果新旧节点是sameVnode(key和sel相同)

  • 调用patchVnode()对比和更新节点
  • 把旧开始和新开始往后移oldStartIdx++/oldEndIdx++

旧结束节点/新结束节点如果新旧节点不是sameVnode,会从后往前比较,比较旧结束节点和新结束节点是否是sameVnode

  • 调用patchVnode()对比和更新节点
  • 把旧结束和新结束往前移oldStartIdx--/oldEndIdx--

是sameVnode调用patchVnode()对比两个节点的差异(文本内容/子元素),更新真实dom

是sameVnode会重用旧节点对应的dom元素,文本内容/子元素不会进行dom操作,

旧开始节点/新结束节点是sameVnode

  • 调用patchVnode()对比和更新节点
  • 把oldStartVnode对应的dom元素,移动到右边,更新索引

旧结束节点/新开始节点是sameVnode

  • 调用patchVnode()对比和更新节点
  • 把oldEndVnode对应的dom元素,移动到左边,更新索引oldEndIdx--/newStartIdx++

都不满足,依次查找是否有相同节点

  • 遍历新的开始节点查找旧节点数组中查找是否有相同key值的节点,找不到新的开始节点就是新节点,创建dom元素插入最前边
  • 找到key值相同节点,判断sel是否相同,不同创建dom元素插入最前边,相同节点赋值给elemToMove,
  • 调用patchVnode()对比和更新节点
  • elemToMove对应的dom元素移动到最前边

循环结束

  • 当老的子节点先遍历完(oldStartIdx>oldEndIdx)

    • 说明新节点有剩余,把剩余节点批量插入到右边
  • 当新的子节点先遍历完(newStartIdx>newEndIdx)

    • 说明老节点有剩余,把剩余节点批量删除