react 和 vue 对比
虚拟 DOM 是什么
- 虚拟 DOM 是什么?
- 虚拟 DOM 是一个轻量级的 JavaScript 对象树,它对应着真实 DOM 树的结构。
- 在 Vue 和 React 中,组件状态(数据)的改变会触发虚拟 DOM 的重新构建。
- 虚拟 DOM 是一个抽象层,它存储了应用的状态和 UI 结构,但并不直接与浏览器交互。
- 工作原理:
- 当应用状态发生变化时,Vue 和 React 会首先生成新的虚拟 DOM 树。
- 然后,它们会将新的虚拟 DOM 与之前的虚拟 DOM 进行比较,找出两者之间的差异,这个过程称为"虚拟 DOM 的协调"。
- 接下来,框架将只更新真正需要改变的部分,而不是重新渲染整个页面。这样可以提高性能,因为直接操作 DOM 通常比操作虚拟 DOM 慢得多。
- 框架差异:
- 虽然 Vue 和 React 都使用了虚拟 DOM 的概念,但它们的实现方式有所不同。Vue 的虚拟 DOM 是响应式的,而 React 的虚拟 DOM 需要手动触发更新。
- 此外,Vue 使用了模板语法,而 React 使用了 JSX,这也导致了一些不同的开发风格。
总之,虚拟 DOM 是 Vue 和 React 等现代前端框架的核心概念,它通过在内存中操作轻量级的 JavaScript 对象来提高性能和开发效率,减少了直接操作 DOM 的成本,并使得组件化开发更加容易。通过对比前后两次虚拟 DOM 的差异,框架可以智能地更新只有改变的部分,而不是整个页面,从而提供更好的用户体验。
为什么要使用虚拟 dom ?
React 和 Vue 使用虚拟 DOM(Virtual DOM),核心目的是在保持开发体验简洁高效的同时,实现高性能的 UI 更新。它不是为了“快”,而是为了在复杂应用中智能、安全、跨平台地更新真实 DOM。
传统的 DOM 操作:
- ❌ 手动 diff 成本高:开发者需精确计算 DOM 变更。
- ❌ 性能难保证:频繁操作 DOM 昂贵(触发重排/重绘)。
- ❌ 代码难以维护:逻辑与 DOM 操作耦合严重。
- ❌ 跨平台困难:Web DOM 无法用于移动端(如 React Native)。
虚拟 DOM 则是在内存中构建一个虚拟的 DOM 树,通过对比新旧虚拟 DOM 树的差异,找出需要更新的部分,然后再一次性地对实际 DOM 进行更新,从而减少了实际 DOM 操作的次数,提高了性能。
具体来说,使用虚拟 DOM 的好处包括:
- ✅ 1. 开发者体验:声明式编程
- ✅ 2. 性能优化:智能 Diff + 批量更新
- 虚拟 DOM 的 Diff 算法(如 React 的 Fiber、Vue 的双端比较)能在 O(n) 时间内找到最小变更集。
- 所有 DOM 操作被合并成一次批量更新,避免多次触发重排/重绘。
- ✅ 3. 跨平台能力
- ✅ 4. 安全性 & 抽象隔离
- 框架控制所有 DOM 写入,可自动做 XSS 防护(如 React 自动转义文本内容)。
- 开发者无需接触底层 DOM API,降低出错概率。
总的来说,虚拟 DOM 技术有效地解决了传统 DOM 操作的性能问题,使得 Vue 和 React 在构建大型、高性能的前端应用时更加高效和灵活。
❌ 误解 1:“虚拟 DOM 比直接操作 DOM 快”
- 不对! 在简单场景下,直接操作 DOM 更快(少一层抽象)。
- 但在复杂、动态的 UI 中,人工优化几乎不可能达到框架的智能程度。
- 虚拟 DOM 的优势是在复杂度和性能之间取得最佳平衡。
❌ 误解 2:“Vue 3 不用虚拟 DOM 了?”
- 错误! Vue 3 仍然使用虚拟 DOM,只是通过编译时优化(如静态提升、Patch Flag)大幅减少了运行时开销。
- 它让虚拟 DOM 更聪明、更高效,而非抛弃它。
有没有不用虚拟 DOM 的框架?
- Svelte:编译时将组件直接转换为高效的命令式 DOM 操作,无运行时虚拟 DOM。
总结
| 目标 | 虚拟 DOM 的作用 |
|---|---|
| 简化开发 | 提供声明式 API,开发者只关心状态,不关心 DOM 操作 |
| 保证性能 | 通过智能 Diff 和批量更新,避免手动优化的复杂性 |
| 跨平台 | 作为平台无关的抽象层,支持 Web、Native、小程序等 |
| 安全可靠 | 框架统一管理 DOM 更新,减少 bug 和安全风险 |
vue 和 react 有哪些区别
- 模板渲染方式不同
- Vue 使用拓展的 HTML 模板语法进行渲染
- React 使用 JSX 语法糖
- 在深层上,模板的原理不同,这才是他们的本质区别:React 是在组件 JS 代码中,通过原生 JS 实现模板中的常见语法,比如插值,条件,循环等,都是通过 JS 语法实现;Vue 是在和组件 JS 代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要 v-if 来实现
- 组件通信不同
- Vue 使用 Props Event Provide/Inject
- React 使用 Props Callback Context
- 监听数据变化的实现原理不同
- Vue 通过 getter/setter 以及一些函数的劫持,能精确知道数据变化,不需要特别的优化就能达到很好的性能
- React 默认是通过比较引用的方式进行的,如果不优化(PureComponent/shouldComponentUpdate)可能导致大量不必要的 VDOM 的重新渲染
- 数据流不同
- vue 支持通过 v-model 进行双向数据绑定
- react 只能通过 onChange/setState 进行绑定
- 为组件拓展功能
- react 使用 HOC
- vue 使用 mixins
vue 和 react 的 diff 算法有什么区别
Vue 和 React 的 Diff 算法(协调算法) 都基于虚拟 DOM,目标是在状态更新时高效找出最小 DOM 变更集。虽然核心思想相似(如“同层比较”、“key 优化”),但在实现策略、优化重点和执行时机上有显著区别。
一、共同基础:为什么需要 Diff?
- 直接对比两棵 DOM 树的所有节点,时间复杂度是 O(n³),性能不可接受。
- React 和 Vue 都采用启发式算法,将复杂度降至 O(n),前提是:
- 只进行同层级比较(不跨层级移动节点);
- 通过
key唯一标识节点,避免误判。
✅ 两者都遵循这一基本原则。
二、React 的 Diff 算法(Fiber Reconciler)
核心特点:
- 深度优先遍历(DFS) + Fiber 链表结构
- 可中断、可恢复、支持优先级调度(Concurrent Mode 基础)
- 统一处理所有类型节点(元素、文本、组件等)
Diff 过程:
- 从根节点开始递归对比新旧虚拟 DOM 树。
- 对每个节点:
- 类型不同(如
<div>→<span>)→ 销毁旧子树,创建新子树。 - 类型相同 → 更新属性(props),并递归对比子节点。
- 类型不同(如
- 对子节点列表:
- 若无
key:逐个对比,遇到不同即停止(效率低)。 - 若有
key:使用 Map 结构建立 key → 节点映射,快速查找复用节点。 - 执行 “最长递增子序列”(LIS)算法,最小化移动操作(React 18+)。
- 若无
优势:
- 支持并发渲染(高优先级更新可打断低优先级)。
- 算法通用性强,适用于任意组件结构。
劣势:
- 运行时计算开销相对较大(需构建 Fiber 树)。
- 开发者需手动优化(如
React.memo)。
三、Vue 的 Diff 算法(Vue 2 vs Vue 3)
▶ Vue 2:双端指针(Two-Pointer)比较
- 仅用于同级子节点列表的 diff。
- 同时从新旧列表的两端向中间比较,共 4 种情况:
- 新首 vs 旧首
- 新尾 vs 旧尾
- 新首 vs 旧尾(节点被移到前面)
- 新尾 vs 旧首(节点被移到后面)
- 若 4 种都不匹配,则用
key查找,否则创建新节点。
✅ 优点:在常见操作(如列表头部/尾部增删)下非常高效。
❌ 缺点:对乱序移动(如 [A,B,C] → [C,A,B])可能产生较多 DOM 操作。
▶ Vue 3:改进的双端 + 编译时优化
Vue 3 的运行时 Diff 更智能,并结合编译器生成的 Patch Flags:
1. 编译时标记(Patch Flags)
- 模板编译时,静态节点被提升(hoisted),动态节点打上标记:
// 编译后 render 函数片段
_createElementVNode("div", { class: _normalizeClass(_ctx.className) }, null, 8 /* PROPS */, ["class"])8表示“只有 props 中的 class 变了”,无需全量 diff。
2. 运行时 Diff 优化
- 子节点 diff 仍用双端指针,但:
- 先检查是否只有单一子节点(直接对比)。
- 若有
key,构建 key → index 映射表,快速定位。 - 对非
key列表,使用最长递增子序列(LIS) 优化移动(类似 React 18)。
3. Block Tree 机制
- 将模板划分为静态 Block 和动态 Block。
- 更新时只 diff 动态 Block,跳过整个静态子树。
✅ 结果:Vue 3 的 Diff 运行时开销显著低于 Vue 2 和 React。
四、关键区别总结
| 维度 | React | Vue 3 |
|---|---|---|
| Diff 触发时机 | 状态更新 → 整个组件重新 render → Diff | 响应式系统精准触发 → 仅 diff 动态部分 |
| 优化重心 | 运行时通用算法(Fiber + LIS) | 编译时 + 运行时协同优化(Patch Flag + Block) |
| 静态节点处理 | 每次 render 都创建 VNode(需 memo 优化) | 编译时提取为常量,永不参与 Diff |
| 列表 Diff | Map + LIS(React 18+) | 双端指针 + LIS(带 key 时) |
| 可中断性 | ✅ 支持(Fiber 架构) | ❌ 不支持(同步执行) |
| 开发者负担 | 需手动优化(memo/useCallback) | 自动优化,几乎无需干预 |
五、举个例子:列表更新
// 旧列表: [A, B, C]
// 新列表: [B, A, C]
- React:
- 用 key 建立映射 → 发现 A、B 位置互换 → 通过 LIS 计算最小移动 → 移动 A 和 B。
- Vue 3:
- 双端比较:新首(B) ≠ 旧首(A),新首(B) = 旧中(B) → 移动 B 到开头;
- 继续比较:新首(A) = 旧首(A) → 复用;
- 最终也只需一次移动。
📌 在大多数场景下,两者 Diff 结果相近,但 Vue 3 因编译优化,运行时更快。
六、总结
| React | Vue 3 | |
|---|---|---|
| 哲学 | “运行时强大,通用灵活” | “编译时聪明,运行时轻量” |
| 优势 | 支持并发、跨平台一致性高 | 更新性能极致优化、开箱即用 |
| 适合 | 复杂交互、需要调度控制的场景 | 高性能 Web 应用、追求极致流畅 |
💡 简单说:
- React 的 Diff 是“聪明的运行时”;
- Vue 3 的 Diff 是“编译器 + 运行时”的联合优化。
两者都极其高效,选择更多取决于项目需求和团队偏好,而非 Diff 算法本身的优劣。
vue 和 react 在 diff 算法上做了哪些改进?
Vue 的改进
- 双向绑定:Vue 引入了双向绑定系统,允许开发者轻松地将视图与模型同步。Vue 的响应式系统使用了 Object.defineProperty,它会追踪数据的依赖关系,只更新发生变化的部分,减少了不必要的 DOM 操作。
- 虚拟 DOM 优化:Vue 在虚拟 DOM 的 diff 算法中实现了一些优化,例如,通过标记静态子树,避免不必要的比较和渲染。
- 异步更新:Vue 的更新是异步的,默认情况下会使用微任务(Promise、MutationObserver)来批量处理 DOM 更新,从而提高性能。
React 的改进
- Fiber 架构:React 引入了 Fiber 架构,它是一个重新设计的协调引擎,使得 React 能够在渲染过程中更好地管理任务的优先级和中断,以提高渲染性能。
- 可中断的渲染:Fiber 架构允许 React 在渲染过程中进行中断和恢复,这意味着 React 可以根据任务的优先级动态调整渲染进程,提高用户体验。
- 增量渲染:React Fiber 支持增量渲染,允许将大型组件树的渲染工作分割成多个步骤,并在多个帧中逐渐完成,以保持界面的响应性。
- Suspense 和 Concurrent Mode:React 引入了 Suspense 和 Concurrent Mode,使得开发者能够更容易地处理异步数据加载、代码拆分和资源加载,从而提高应用的性能和用户体验。
- memoization:React 采用了 memoization 技术,通过缓存组件的渲染结果,减少了重复渲染的成本。
vue2 在 diff 算法上做了哪些优化
- 虚拟 DOM 的双端比较:
- Vue 2 中使用了双端比较的策略,在对比新旧虚拟 DOM 树时,会同时从新旧两棵树的头部和尾部开始遍历,以尽量减少比较的节点数量。这种优化策略使得 diff 过程更加高效。
- 静态节点优化:
- Vue 2 中引入了静态节点优化的策略,通过 v-once 指令将不需要频繁更新的静态节点提升为静态内容,从而减少渲染开销。这样可以避免不必要的 diff 操作和 DOM 更新。
- DOM 更新的最小化:
- Vue 2 会尽量减少对 DOM 的直接操作,而是通过虚拟 DOM 进行 diff 比较,并生成最小化的更新操作,然后批量更新到真实 DOM 中。这样可以减少 DOM 操作的次数,提高渲染性能。
- 异步更新队列(批量更新):
- Vue 2 使用了异步更新队列的策略,在数据变化时并不会立即触发视图更新,而是将更新操作放入异步队列中,然后在下一个事件循环中进行处理。这样可以将多个更新操作合并成一个批量更新,提高性能和效率。
这些优化措施使得 Vue 2 在 diff 算法上的性能得到了一定程度的提升,尤其是在处理大型应用和大量数据更新时,能够更高效地进行虚拟 DOM 的 diff 比较和 DOM 更新操作。
vue3 相对于 vue2,有什么改进?
Vue 3 相对于 Vue 2 进行了许多改进和优化,主要包括以下几个方面:
- 性能优化:
- 引入了 Patch Flag(静态标记) 和 Dynamic Directive(动态指令),可以在更新过程中跳过不需要比较的节点,减少了不必要的 diff 操作。
- Vue 3 支持静态节点提升(Static Node Hoisting),将不需要响应式更新的静态节点提升到渲染函数之外,减少了渲染的开销。
- Vue 3 使用了 Tree-shaking 技术,可以更好地优化打包后的代码,减小应用的体积。
- Composition API:
- Vue 3 引入了 Composition API,提供了一种更灵活、更易于组织代码的方式来编写组件逻辑。Composition API 可以将组件的逻辑按照功能划分为多个函数,使得代码更易于维护和复用。
- TypeScript 支持:
- Vue 3 对 TypeScript 的支持更加友好,通过重新设计 API 和改进类型定义,提供了更好的类型推断和编辑器支持,使得开发者可以更轻松地使用 TypeScript 来开发 Vue 应用。
- 更好的 TypeScript 集成:
- Vue 3 改进了对 TypeScript 的支持,包括对 Vue 组件的类型推断的改进、更好的编辑器支持以及更准确的类型检查。
- 更好的递归组件支持:
- Vue 3 对递归组件的支持更加友好,提供了新的
<teleport>组件和 v-model 的改进,使得递归组件的使用更加简洁和灵活。
- Vue 3 对递归组件的支持更加友好,提供了新的
- 更好的响应式系统:
- Vue 3 对响应式系统进行了改进,提供了更强大的响应式 API,包括 ref、reactive、computed、watch 等,使得状态管理更加灵活和方便。
- 更好的编译器优化:
- Vue 3 的编译器进行了改进,提供了更好的优化和更好的错误提示,使得开发者可以更轻松地编写和调试 Vue 应用。
总的来说,Vue 3 在性能、开发体验、TypeScript 支持和编译器优化等方面都进行了许多改进和优化,使得 Vue 更加强大、更易于使用和维护。
Proxy 为什么要替代 Object.defineProperty:
- 更强大的功能:Proxy 对象提供了更强大和灵活的功能,可以监听更多类型的操作,包括属性的读取、赋值、删除等,而 Object.defineProperty 只能监听属性的读取和赋值。
- 更方便的语法:使用 Proxy 可以更直观和简洁地定义响应式行为,而不需要像使用 Object.defineProperty 那样需要逐个定义属性的 getter 和 setter 方法。
- 更易于扩展:Proxy 可以轻松地实现递归监听和数组的监听,而 Object.defineProperty 需要额外的逻辑来处理嵌套对象和数组的情况。
- 更好的性能:Proxy 对象相对于 Object.defineProperty 有更好的性能,特别是在监听大型对象或数组时,如果使用 Object.defineProperty,你需要逐个定义每个属性的 getter 和 setter 方法,这可能会导致性能下降;而使用 Proxy 对象则可以直接对整个对象或数组进行监听,而不需要逐个定义每个属性的 getter 和 setter 方法。Proxy 可以监听对象的所有操作,包括属性的读取、赋值、删除等,而且使用 Proxy 对象时可以提供更加简洁和优雅的语法。。
- 更好的兼容性:Proxy 是 ES6 新增的特性,而 Object.defineProperty 有一些限制和兼容性问题,尤其是在 IE8 及以下版本的浏览器中不支持,使用 Proxy 可以避免这些兼容性问题。
vue3 在 diff 算法上的优化
- 双端比较(双指针算法):
- Vue 3 引入了双端比较(双指针算法),在某些情况下可以减少比较的节点数量。双端比较会从新旧两个虚拟 DOM 的头尾同时开始遍历,每次比较一对节点,直到两个指针相遇。
- 静态节点提升(Static Node Hoisting):
- Vue 3 引入了静态节点提升技术,能够将不需要响应式更新的静态节点提升到渲染函数之外,减少不必要的比较和渲染,提高渲染性能。
- 事件侦听器的优化:
- Vue 3 使用了事件侦听器的缓存策略,避免了在每次更新时重新创建事件侦听器,提高了性能。
- 标记静态根节点:
- Vue 3 在编译阶段会标记出静态根节点,这些节点不需要进行比较,可以直接跳过,减少了不必要的比较开销。
- Patch Flag:
- Vue 3 使用 Patch Flag 来标记节点的动态内容,这样在 diff 过程中可以快速判断出哪些节点需要进行比较,从而减少了比较的节点数量。
这些优化措施使得 Vue 3 在 diff 算法上的性能得到了显著的提升,特别是在大型应用中能够更高效地处理更新和渲染,提升了整体的性能表现。虽然 Vue 2 和 Vue 3 都引入了双端比较(双指针算法),但它们的实现细节可能有所不同。基本的双端比较思想是相似的,即从新旧两个虚拟 DOM 树的头部和尾部同时开始遍历,每次比较一对节点,直到两个指针相遇。然而,Vue 3 可能对此进行了更深层次的优化,以提高性能和效率。 Vue 3 在其源代码中进行了大量的改进和优化,包括对虚拟 DOM 的 diff 算法进行了重构和改进。因此,Vue 3 的双端比较可能会使用更高效的算法,或者采用了一些 Vue 2 中没有的新技术。例如,Vue 3 引入了 Patch Flag 来标记节点的动态内容,这可以帮助 diff 算法更快地识别出需要更新的节点,从而提高性能。 因此,尽管 Vue 2 和 Vue 3 的双端比较的基本思想是相似的,但 Vue 3 可能会在实现细节上进行了更多的改进,以提高性能和效率。