aurora blog
  • JS

    • 基本汇总
    • Date时间
    • Array方法
    • String 方法
    • Object方法
    • RegExp正则
    • Es6 新特性等
    • Event-Loop
    • Http and Https
    • for in和for of区别
    • Web Worker
    • Promise && async
    • 堆内存 & 栈内存
    • JS设计模式探索
    • npm & yarn
    • Fetch和Axios的区别
    • 学习及面试问题整理
    • URL 输入到页面加载过程
    • 跨域&nginx本地项目代理
  • FE框架

    • react

      • 基本用法
      • react生命周期
      • hooks 16.8版本后
      • Route原理
      • Redux源码解析
      • React16 Fiber
      • React-VirtualDOM
      • React事件委托机制
    • vue

      • vue 基本用法
      • vue 生命周期
      • VirtualDOM
      • vue 事件委托
      • vue 架构
      • vue 状态管理
      • 问题等
    • React-Native

      • React-Native 基本用法
    • 微前端

      • 遇到的问题
    • 鸿蒙 harmony

      • harmony 基础
  • 构建工具

    • webpack

      • Webpack配置详解
      • Webpack的使用
      • Babel-polyfill
      • webpack面试题
    • vite

      • vite基本配置
  • Typescript

    • Typescript详解
  • Servers

    • Nodejs
    • Nginx
  • Git命令

    • git常用规范
  • 数据库

    • mongodb
    • mongodb
  • Other

    • Jenkins自动化部署

Vue2 & Vue3 虚拟 DOM 原理与对比

  • 什么是虚拟 DOM
  • Vue2 虚拟 DOM 原理
  • Vue3 虚拟 DOM 优化
  • Vue2 与 Vue3 虚拟 DOM 对比与优势
  • 为什么要更新虚拟 DOM?
  • 什么是 Diff 算法
  • Vue2 Diff 算法原理
  • Vue3 Diff 算法优化
  • 总结对比

什么是虚拟 DOM

  • 虚拟 DOM(Virtual DOM)是用 JS 对象模拟真实 DOM 结构,更新时通过 diff 算法找出变化部分,最后只操作必要的真实 DOM,提高性能。

Vue2 虚拟 DOM 原理

  • Vue2 使用虚拟 DOM,采用同步递归 diff 算法。
  • 每次数据变化,重新生成新的虚拟 DOM 树,与旧树对比,生成 patch,批量更新真实 DOM。
  • 虚拟 DOM 结构简单,性能在中小型项目表现良好。

代码示例:

// Vue2 内部虚拟 DOM 节点结构
const vnode = {
  tag: 'div',
  data: { id: 'app' },
  children: [
    { tag: 'span', text: 'hello' }
  ]
};

Vue3 虚拟 DOM 优化

  • Vue3 虚拟 DOM diff 算法重写,性能更高,减少不必要的节点比对。
  • 支持 Fragment(多个根节点)、Teleport(跨层渲染)、Suspense(异步组件),灵活性更强。
  • 更好地支持 TypeScript,源码更现代。
  • 渲染过程更高效,适合大型复杂项目。

代码示例:

// Vue3 内部虚拟 DOM 节点结构更精简,支持更多类型
const vnode = {
  type: 'div',
  props: { id: 'app' },
  children: [
    { type: 'span', children: 'hello' }
  ]
};

Vue2 与 Vue3 虚拟 DOM 对比与优势

特性Vue2 虚拟 DOMVue3 虚拟 DOM
diff 算法同步递归重写,更高效
性能较好更高,适合大型项目
支持特性单根节点Fragment、Teleport、Suspense
类型支持JSTypeScript 原生支持
灵活性一般更强

为什么要更新虚拟 DOM?

  • Vue2 虚拟 DOM在大数据量和复杂场景下性能瓶颈明显。
  • Vue3 重写虚拟 DOM和diff算法,提升渲染速度,减少内存占用,支持更多新特性。
  • 更好地适配现代前端需求和大型项目。

Vue2 & Vue3 虚拟 DOM Diff 算法深入讲解

什么是 Diff 算法

Diff 算法是虚拟 DOM 的核心,用于比较新旧虚拟 DOM 树,找出变化部分,生成 patch,最后只更新必要的真实 DOM,提高性能。


Vue2 Diff 算法原理

  • Vue2 的 Diff 算法采用同层比较和递归遍历,只比较同一层的节点,不跨层查找。
  • 主要流程:
    1. 遍历新旧 children 数组,按顺序比较节点类型和 key。
    2. 如果 key 和类型都相同,则复用旧节点,只更新属性。
    3. 如果 key 不同,则删除旧节点、插入新节点。
    4. 对于没有 key 的节点,采用顺序比较,性能一般。
  • Vue2 的 Diff 算法适合中小型项目,但在复杂场景下性能有限。

简化代码示例:

function diff(oldChildren, newChildren) {
  let patches = [];
  for (let i = 0; i < Math.max(oldChildren.length, newChildren.length); i++) {
    const oldVnode = oldChildren[i];
    const newVnode = newChildren[i];
    if (!oldVnode) {
      patches.push({ type: 'add', vnode: newVnode });
    } else if (!newVnode) {
      patches.push({ type: 'remove', vnode: oldVnode });
    } else if (oldVnode.key === newVnode.key) {
      patches.push({ type: 'update', vnode: newVnode });
    } else {
      patches.push({ type: 'replace', vnode: newVnode });
    }
  }
  return patches;
}

Vue3 Diff 算法优化

  • Vue3 对 Diff 算法进行了重写,采用双端比较和**最长递增子序列(LIS)**优化,减少不必要的 DOM 操作。
  • 主要流程:
    1. 首尾指针分别比较新旧 children 数组的头尾节点,优先处理相同的节点。
    2. 利用 key 快速定位节点,移动或复用节点,减少删除和插入操作。
    3. 通过 LIS 算法找到最少需要移动的节点,提升性能。
    4. 支持 Fragment、Teleport、Suspense 等新特性,灵活性更强。
  • Vue3 的 Diff 算法在大数据量和复杂场景下性能显著提升。

简化代码示例(双端比较思想):

function diffVue3(oldChildren, newChildren) {
  let oldStart = 0, newStart = 0;
  let oldEnd = oldChildren.length - 1, newEnd = newChildren.length - 1;
  while (oldStart <= oldEnd && newStart <= newEnd) {
    if (oldChildren[oldStart].key === newChildren[newStart].key) {
      // 更新节点
      oldStart++; newStart++;
    } else if (oldChildren[oldEnd].key === newChildren[newEnd].key) {
      // 更新节点
      oldEnd--; newEnd--;
    } else {
      // 复杂场景下用 key 查找和移动节点
      // ...省略
      break;
    }
  }
  // 处理剩余新增或删除节点
}

LIS 算法用于最少移动节点:

// Vue3 内部用到的最长递增子序列算法
function getLIS(arr) {
  const p = arr.slice();
  const result = [0];
  let i, j, u, v, c;
  const len = arr.length;
  for (i = 0; i < len; i++) {
    if (arr[i] !== 0) {
      j = result[result.length - 1];
      if (arr[j] < arr[i]) {
        p[i] = j;
        result.push(i);
        continue;
      }
      u = 0; v = result.length - 1;
      while (u < v) {
        c = ((u + v) / 2) | 0;
        if (arr[result[c]] < arr[i]) u = c + 1;
        else v = c;
      }
      if (arr[i] < arr[result[u]]) {
        if (u > 0) p[i] = result[u - 1];
        result[u] = i;
      }
    }
  }
  u = result.length; v = result[u - 1];
  while (u-- > 0) {
    result[u] = v;
    v = p[v];
  }
  return result;
}

总结对比

特性Vue2 DiffVue3 Diff(优化)
比较方式同层递归双端比较 + LIS
性能一般更高,移动节点更少
支持特性单根节点Fragment、Teleport等
灵活性一般更强
适用场景中小型项目大型复杂项目

为什么 Vue3 要升级 Diff 算法?

  • 提升大数据量和复杂场景下的性能,减少 DOM 操作次数。
  • 支持更多新特性和更灵活的组件结构。
  • 更好地适配现代前端需求和大型项目。

更多内容

最近更新:: 2025/8/7 15:46
Contributors: liyulai
Prev
vue 生命周期
Next
vue 事件委托