1. 用 JavaScript 对象描述 DOM 树结构,然后用它来构建真正的 DOM 树插入文档
  2. 当状态发生改变之后,重新构造新的 JavaScript 对象结构,新的和旧的作对比,得出差异
  3. 针对差异之处,进行视图更新

    创建 VDOM 挂载真实 DOM

    1. const vDom = createElement(
    2. 'ul',
    3. { class: 'list', style: 'width:300px;height:300px;background-color:orange' },
    4. [
    5. createElement('li', { class: 'item', 'data-index': 0 }, [
    6. createElement('p', { class: 'text' }, ['第1个列表项']),
    7. ]),
    8. createElement('li', { class: 'item', 'data-index': 1 }, [
    9. createElement('p', { class: 'text' }, ['第2个列表项']),
    10. ]),
    11. createElement('li', { class: 'item', 'data-index': 2 }, ['第3个列表项']),
    12. ]
    13. );

    VDom
    点击查看【codepen】
    image.png
    Virutal DOM 转为 Real DOM
    点击查看【codepen】

    DOM Diff

    目的:找出旧新节点的差异,以最少性能消耗代价去操作 DOM 打补丁
    算法规则

  4. 同层级对比

  5. Key 索引策略对比
  6. 新旧节点顺序改变位置替换
  7. 深度优先遍历

    tree diff

    虚拟 DOM - 图2
  • 同层级 DOM 节点对比,使时间复杂度 虚拟 DOM - 图3
  • 对不同层级的节点,只有创建和删除操作 :::info 保持稳定的 DOM 结构会有助于性能的提升 :::

    element diff

    虚拟 DOM - 图4

  • 深度优先遍历

  • 通过设置唯一 Key 的策略,对 element diff 进行算法优化 :::info 尽量减少类似将最后一个节点移动到列表首部的操作 :::

    component diff

  • 同一类型组件 会进行 Virtual DOM 进行比较

  • 不同类型组件 会替换整个组件下的子节点
  • React 提供了一个 shouldComponentUpdate,决定是否更新

深度剖析:如何实现一个 Virtual DOM 算法

通过 diff 生成补丁

image.png
目标是生成补丁,也是一个对象

  1. const patches = {
  2. 0: [
  3. {
  4. type: 'ATTR',
  5. attrs: {
  6. class:'list-wrap'
  7. }
  8. }
  9. ],
  10. 2: [
  11. {
  12. type: 'ATTR',
  13. attrs: {
  14. class:'ttile'
  15. }
  16. }
  17. ],
  18. 3: [
  19. {
  20. type: 'TEXT',
  21. text: '特殊列表项'
  22. }
  23. ],
  24. 6: [
  25. {
  26. type: 'REMOVE',
  27. index: 6
  28. }
  29. ],
  30. 7: [
  31. {
  32. type: 'REPLACE',
  33. newNode: newNode
  34. }
  35. ]
  36. }

新旧 VDOM 作对比 diff
点击查看【codepen】

  1. const patches = domDiff(vDom1, vDom2);

patch 打补丁

点击查看【codepen】

  1. doPatch(rDom, patches);