33-mini-vue 更新element的children-双端对比diff算法

更新element的children-双端对比diff算法

  1. 中间对比

  2. 案例

    • a b ( c y e ) f g < -------- >
    • a b ( e d c ) f g
  3. 情况分析

    • 创建新的(d) (在老的里面不存在,新的里面存在)
    • 删除老的(y) (在老的里面存在,新的里面不存在)
    • 移动(c,e) (节点存在于新的和老的里面,但是位置变了)
  4. 针对相应的情况进行实现功能

    1. 老节点里面有,新节点里面无 如何进行判断呢
      • 遍历新节点进行查找是否存在老节点,我们使用双端对比,减少了O(n) 里面的 n
      • 直接使用 key来进行判断,时间空间复杂度属于 O(1)
    2. 测试案例
    js 复制代码
    // 5.1 
    // a b ( c d ) f g
    // a b ( e c ) f g
    // d 节点在新的里面是没有的 - 需要删除掉
    // c 节点 props 也发生了变化
    const prevChldren = [
      h('p', { key: 'A'}, "A"),
      h('p', { key: 'B'}, "B"),
      h('p', { key: 'C', id: 'c-prev'}, "C"),
      h('p', { key: 'D'}, "D"),
      h('p', { key: 'F'}, "F"),
      h('p', { key: 'G'}, "G"),
    ]
    const nextChildren = [
      h('p', { key: 'A'},'A'),
      h('p', { key: 'B'},'B'),
      h('p', { key: 'E'},'E'),
      h('p', { key: 'C', id: 'c-next'},'C'),
      h('p', { key: 'F'},'F'),
      h('p', { key: 'G'},'G')
    ]
  5. 实现过程

    1. 观察我们发现上面的测试案例, prevChildren 与 nextChildren ,我们先研究的点是

      • 新的里面没有D,进行删除
      • 新的里面 C 的 id 属性值不同,进行修改
    2. 功能实现

    js 复制代码
    // 新的比老的多
    if (i > e1) {
      if (i <= e2) {
        const nextPos = i + 1
        const anchor = nextPos < l2 ? c2[nextPos].el : null
        while (i <= e2) {
          patch(null, c2[i], container, parentComponent, anchor)
          i++
        }
      }
      // 老的比新的多
    } else if (i > e2) {
      while (i <= e1) {
        hostPatchRemove(c1[i].el)
        i++
      }
    } else {
      // ✅ 中间对比
      let s1 = i
      let s2 = i
      let toBePatched = e2 - s2 + 1 // ✅ 优化
      let patched = 0 // ✅ 优化
      const keyToNewIndexMap = new Map()
    
      for (let i = s2; i <= e2; i++) { // 将新节点的每个元素的 key 存入 map
        const nextChild = c2[i]
        keyToNewIndexMap.set(nextChild.key, i)
      }
    
      for (let i = s1; i <= e1; i++) {
        const prevChild = c1[i]
        if (patched >= toBePatched) { // ✅ 优化
          hostPatchRemove(prevChild.el)
          continue;
        }
        // null,unfined
        let newIndex
        // ✅ 看老节点的 key 能不能和新节点匹配上
        if (prevChild.key != null) {
          newIndex = keyToNewIndexMap.get(prevChild.key)
        } else {
          for (let j = s2; j <= e2; j++) {
            if (isSameVNodeType(prevChild, c2[j])) {
              newIndex = j
              break
            }
          }
    
        }
        if (newIndex === undefined) { // ✅ 新节点里面没有,就把老节点删除
          hostPatchRemove(prevChild.el)
        } else { // ✅ 新节点里面有就进行对比渲染
          patch(prevChild, c2[newIndex], container, parentComponent, null)
          patched++
        }
      }
    }
相关推荐
Kakarotto2 小时前
Canvas 直线点击事件处理优化
javascript·vue.js·canvas
ZhengEnCi2 小时前
08c. 检索算法与策略-混合检索
后端·python·算法
进击的尘埃3 小时前
Playwright Component Testing 拆到底:组件怎么挂上去的,快照怎么在 CI 里不翻车
javascript
左夕3 小时前
最基础的类型检测工具——typeof, instanceof
前端·javascript
yuki_uix3 小时前
递归:别再"展开脑补"了,学会"信任"才是关键
前端·javascript
程序员小崔日记3 小时前
大三备战考研 + 找实习:我整理了 20 道必会的时间复杂度题(建议收藏)
算法·408·计算机考研
lizhongxuan4 小时前
AI小镇 - 涌现
算法·架构
用户5757303346246 小时前
🐱 从“猫厂”倒闭到“鸭子”横行:一篇让你笑出腹肌的 JS 面向对象指南
javascript
码路飞6 小时前
GPT-5.4 Computer Use 实战:3 步让 AI 操控浏览器帮你干活 🖥️
java·javascript
进击的尘埃6 小时前
Service Worker 离线缓存这事,没你想的那么简单
javascript