vue3中性能优化

447 阅读5分钟

一、性能优化

Vue 在大多数常见场景下性能都是很优秀的,通常不需要手动优化。

首先,让我们区分一下 web 应用性能的两个主要方面:

  • 页面加载性能:首次访问时,应用展示出内容与达到可交互状态的速度。这通常会用 Google 所定义的一系列 Web 指标 (Web Vitals) 来进行衡量,如最大内容绘制 (Largest Contentful Paint,缩写为 LCP) 和首次输入延迟 (First Input Delay,缩写为 FID)。
  • 更新性能:应用响应用户输入更新的速度。比如当用户在搜索框中输入时,显示结果列表的更新速度,或者用户在一个单页面应用 (SPA) 中点击链接,跳转页面时的切换速度。

1、分析性能工具:

1. 用于生产部署的负载性能分析:

2. 用于本地开发期间的性能分析:

性能优化主要是在两方面进行,加载方面与更新方面

2、性能优化:加载方面

1. 选择正确的架构

  • 对于首屏加载没有要求:使用SPA + 接口
  • 有一定的营销:主应用SPA + SSG静态站点内容
  • 对于首屏加载要求很高:SSR或者SSG

SSR与SSG可见:juejin.cn/editor/draf…

2. 对于包体积与 Tree-shaking 优化

一个最有效的提升页面加载速度的方法就是压缩 JavaScript 打包产物的体积

  1. 尽可能采用构建工具进行构建打包
  • 使用vite,rollup,webpack等进行打包,会自动进行tree-shaking,没有使用的包不进行打包,会移除
  • 使用构建工具后,会预编译,不用在浏览器上加载vue编译器,相对来说减少14kb并避免运行时编译开销
  1. 在引入第三包时,进行判断,避免引入过重依赖
  • 尽量使用ES模块依赖,对于tree-shaking更友好,例如lodash-es比lodash更好
  • 如果引入包体积过大,功能很小,性能远小于功能的编写,应该对于性能排在更优位置

3. 代码分割

对代码进行分割,将js包拆分为多个较小的,多个包可以按需或者并行加载,先只加载立即执行的,剩下的进行按需加载。

  • 像 Rollup (Vite 就是基于它之上开发的) 或者 webpack 这样的打包工具可以通过分析 ESM 动态导入的语法来自动进行代码分割:
// lazy.js 及其依赖会被拆分到一个单独的文件中
// 并只在 `loadLazy()` 调用时才加载
function loadLazy() {
  return import('./lazy.js')
}
  • 懒加载对于页面初次加载时的优化帮助极大,它帮助应用暂时略过了那些不是立即需要的功能。在 Vue 应用中,这可以与 Vue 的异步组件搭配使用,为组件树创建分离的代码块
import { defineAsyncComponent } from 'vue'

// 会为 Foo.vue 及其依赖创建单独的一个块
// 它只会按需加载
//(即该异步组件在页面中被渲染时)
const Foo = defineAsyncComponent(() => import('./Foo.vue'))
  • 对于使用了 Vue Router 的应用,强烈建议使用异步组件作为路由组件。Vue Router 已经显性地支持了独立于 defineAsyncComponent 的懒加载

3、性能优化:更新优化

1. 让传给子组件的 props 尽量保持稳定

父组件传给子组件的props尽量保持稳定状态,比如可以将子组件中的判断逻辑放入到父组件中,当activeId与id一样时,渲染子组件,这样就可以不用在每次id变化时渲染子组件

<ListItem
  v-for="item in list"
  :id="item.id"
  :active-id="activeId" />
// 改为
<ListItem
  v-for="item in list"
  :id="item.id"
  :active="item.id === activeId" />

2. 使用v-once,只渲染一次,以后会跳过,当作静态内容渲染

用来渲染依赖运行时数据但无需再更新的内容。它的整个子树都会在未来的更新中被跳过

3. 渲染超过1000条数据时,可用v-memo

v-memo有条件的跳过子树,比如v-for树型列表中,v-memo缓存一个模板的子树,传入数组,当数组中每个值与最后一次一样,则不更新,vnode创建也会跳过。

与v-for一起使用,在同一层,当v-memo条件变化时更新

4. computed稳定性好

computed会进行缓存,只有在依赖值变化的时候才会进行重新计算。不过要是返回一个对象,应手动进行深层次比较,没有变化返回旧值,否则返回新值。

4、大型数据下优化:同时优化加载和更新

1. 渲染成千上万列表 —— 使用虚拟列表

渲染成千上万列表时,浏览器需要处理大量DOM节点,会变得很慢,可以使用虚拟列表,通过列表虚拟化提升性能,只渲染用户视野中的数据,可以使用插件vue-virtual-scroller

2. 减少大型不可变数据的响应性开销,使用浅层式API

例如一次渲染需要访问 100,000+ 个属性时,才会变得比较明显。因此,它只会影响少数特定的场景。使用shallowRef()shallowReactive()。不过浅层API只用于组件中的根级状态,深层对象不做处理,只有根状态改变时才会触发,应该用于特定场景。

3. 复用内容时,避免不必要的组件抽象,组件实例比DOM节点渲染昂贵的多

只减少几个组件实例对于性能不会有明显的改善,所以如果一个用于抽象的组件在应用中只会渲染几次,就不用操心去优化它了。考虑这种优化的最佳场景还是在大型列表中。想象一下一个有 100 项的列表,每项的组件都包含许多子组件。在这里去掉一个不必要的组件抽象,可能会减少数百个组件实例的无谓性能消耗。