Vue3.x的性能提升 | 8月更文挑战

231 阅读3分钟

响应式系统提升

  • Vue2.0中响应式系统的核心defineProperty

    在初始化时会遍历data中的所有成员,通过defineProperty将对象的属性转换为getter和setter,如果对象中的成员又是对象的话需要递归处理里面的每一个属性,因为是在初始化时进行的defineProperty,所以没有使用的属性也进行了响应化处理

  • Vue3.0中使用Proxy对象重写响应式系统

    使用的Es6后新增的Proxy对象,本身性能就比defineProperty要好。另外代理对象可以拦截属性的访问、赋值、删除等操作,不需要初始化时遍历所有的属性。另外多层嵌套属性只有在访问时才会递归处理下一层属性

    • 可以监听动态新增的属性,vue2.0中需要调用vue.set()进行处理

    • 可以监听删除的属性,vue2.0监听不到属性的删除

    • 可以监听数组的索引和length属性,vue2.0监听不到这两个属性的操作

    使用Proxy提升了响应式的性能和功能

编译优化

通过优化编译过程和重写虚拟DOM让首次渲染和更新的性能有了大幅度提升

  • vue2中通过标记静态根节点优化了diff的过程

    V2.0中模板首先要编译成render函数,这个过程在构建过程中完成,在编译时会编译静态根节点和静态节点,静态根节点中要求必须有一个静态子节点,当组件的状态发生变化后会触发watcher的update,最终去执行虚拟DOM的patch操作,遍历所有虚拟节点找到差异,更新到真实DOM上。diff的过程中会比较整个虚拟DOM,先对比新旧的div以及它的属性,然后再对比它的子节点,vue2中渲染的最小单位是组件。vue2中diff的过程会跳过静态根节点,因为静态根节点的内容不会发生变化,也就是vue2中通过标记静态根节点优化了diff的过程,但是静态节点还需要diff,这个过程没有被优化。

  • vue3中标记和提升所有的静态节点,diff时只需要对比动态节点内容

    • 新引入Fragments(片段)特性,模板中不需要再创建一个唯一的根节点,模板里可以直接放文本内容或者很多同级的标签
    • 静态提升,静态节点都会被提升到render 的外部,只有初始化时会被创建,再次调用render时不会再次创建,可以直接重用这些静态节点对应的vnode
    • Patch flag
    • 缓存事件处理函数减少了不必要的更新操作

源码体积的优化

  • Vue3中移除了一些不常用的API
    • 例如:inline-template、filter等可以让最终代码的体积变小
  • 对Tree-shaking支持更好,Tree-shaking依赖Es-module,也就是export import。通过编辑阶段的静态分析找到没有引入的模块在打包时直接过滤掉,让打包后的体积更小。