Vue 2.0 与 Vue 3.0 的差异与性能提升
响应式系统
- Vue 2.0:使用
Object.defineProperty
实现数据响应式,存在无法检测对象属性动态添加/删除及数组下标和length
属性变化的问题。 - Vue 3.0:采用 ES6
Proxy
API,全面代理对象所有属性,包括动态添加/删除属性及数组操作,使响应式系统更健壮、高效。
Composition API
- Vue 2.0:使用 Options API,数据、方法、计算属性和生命周期钩子分散在不同选项中。
- Vue 3.0:引入 Composition API,基于函数式编程风格,通过
setup()
函数使用ref
、reactive
、computed
等组合函数管理组件状态和逻辑,增强代码复用和组织灵活性。
Tree-Shaking
- Vue 3.0:对代码库进行重构,提高模块化程度,便于进行Tree-Shaking。生产环境中,打包工具可剔除未使用代码,减小生成的JavaScript文件体积,提升加载速度。
优化的虚拟DOM算法
- Vue 3.0:引入Fragment(片段)、Teleport(传送)和Suspense(预留)等新特性,优化比较算法,提高更新DOM效率。
更好的TypeScript支持
- Vue 3.0:设计之初即考虑原生TypeScript支持,提供完善的类型声明文件,便于大型项目中使用TypeScript开发。
组件编译器改进
- Vue 3.0:优化模板编译和渲染函数语法,提升编译器效率。
初始化性能提升
- Vue 3.0:初始化过程比Vue 2.0更快,尤其在大型应用中表现更明显。
创建和挂载组件的优化
- Vue 3.0:使用
createApp
方法和mount
方法代替全局Vue实例和new Vue()
,新API设计更易理解和使用,同时带来性能提升。
Vue 3.0 虚拟DOM优化的主要方面
Fragment(片段)支持
- Vue 2.x每个组件必须有一个根元素;Vue 3.0引入Fragment,允许组件返回多个根元素,减少不必要的DOM元素。
Teleport(传送)功能
- Teleport允许将组件渲染到DOM树任意位置,避免不必要的DOM移动和重绘,提高性能。
Suspense(预留)组件
- Suspense处理异步加载组件场景,显示备用内容或加载指示器直至资源加载完成,提升用户体验并减少DOM操作。
优化的比较算法
- 使用“静态标记”和“形状假设”技术识别多次渲染中不变的节点,跳过比较过程;通过比较DOM树形状而非每个属性优化比较过程。
更细粒度的组件更新
- 只有受影响的组件及其子组件进行更新,而非整个组件树,减少不必要的更新和DOM操作。
更快的创建和更新过程
- 通过改进VNode创建和更新过程,如使用稀疏数组存储动态属性,提高效率。
Vue 3.0 DOM 更新 diff 算法优化
Vue2.0 Diff 算法
当VM层(data层)数据发生变化后,setter()方法会调用dep.notify()
方法(发布者),通知所有订阅者。订阅者会调用isSameNode()
方法,对传入的虚拟DOM节点进行新旧比对。如果发现该对象中tag
和key
都相同,就会认为两者是同一节点,直接将新的DOM对象返回渲染。如果不同,则调用patch()
方法。patch()
方法主要负责对不同的节点进行判断,如是否含有子节点或文本节点等。
- 不含子节点:对比文本节点;
- 不含文本节点:直接删除;
- 含有子节点:调用
updateChildren()
方法,遍历并对比、更新DOM树。
子节点比对通过遍历二叉树实现,利用oldStartIndex
, oldEndIndex
, newStartIndex
, newEndIndex
指针进行。
Vue3.0优化点
静态提升(Static Hoisting)
- 模板编译阶段将不会因数据变化而动态渲染的部分提前编译为静态HTML,首次渲染时直接插入DOM,避免更新时重新生成和比较。
形状假设(Shape Assumptions)
- 基于DOM树结构相对稳定的观察,虚拟DOM算法在比较新旧VNode树时对形状做出假设。若节点标签名和属性相同,可能假设子节点形状相同,跳过深度比较。当形状假设不成立时,回退至深度优先遍历和比较。
稀疏数组(Sparse Arrays)
- 用于优化动态属性处理,存储大量动态属性时使用稀疏数组,通过索引表示属性名,值存储在对应索引位置,减少内存占用,提高属性更新速度。