首页 > 其他分享 >第三十八篇 vue - 最佳实践 - 性能优化

第三十八篇 vue - 最佳实践 - 性能优化

时间:2023-04-04 23:57:25浏览次数:43  
标签:vue 渲染 性能 Vue 组件 页面 优化 第三十八 加载

概述

Vue 在大多数常见场景下性能都是很优秀的,通常不需要手动优化。然而,总会有一些具有挑战性的场景需要进行针对性的微调。在本节中,我们将讨论用 Vue 开发的应用在性能方面该注意些什么

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

  1、页面加载性能
  
    首次访问时,应用展示出内容与达到可交互状态的速度。这通常会用 Google 所定义的一系列 Web 指标 (Web Vitals) 来进行衡量,如最大内容绘制 (Largest Contentful Paint,缩写为 LCP) 和首次输入延迟 (First Input Delay,缩写为 FID)。

  2、更新性能
  
    应用响应用户输入更新的速度。比如当用户在搜索框中输入时结果列表的更新速度,或者用户在一个单页面应用 (SPA) 中点击链接跳转页面时的切换速度。

虽然最理想的情况是将两者都最大化,但是不同的前端架构往往会影响到在这些方面是否能达到更理想的性能。此外,你所构建的应用的类型极大地影响了你在性能方面应该优先考虑的问题。因此,优化性能的第一步是为你的应用类型确定合适的架构

分析选项

为了提高性能,我们首先需要知道如何衡量它。在这方面,有一些很棒的工具可以提供帮助:

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

  1、PageSpeed Insights
  
  2、WebPageTest
  
2、用于本地开发期间的性能分析:

  1、Chrome 开发者工具“性能”面板

   app.config.performance 将会开启 Vue 特有的性能标记,标记在 Chrome 开发者工具的  性能时间线上
   
  2、Vue 开发者扩展也提供了性能分析的功能。

页面加载优化

页面加载优化有许多跟框架无关的方面 - 这份 web.dev 指南提供了一个全面的总结。这里,我们将主要关注和 Vue 相关的技巧
选用正确的架构
选用正确的架构

如果你的用例对页面加载性能很敏感,请避免将其部署为纯客户端的 SPA,而是让服务器直接发送包含用户想要查看的内容的 HTML 代码。纯客户端渲染存在首屏加载缓慢的问题,这可以通过服务器端渲染 (SSR) 或静态站点生成 (SSG) 来缓解。查看 SSR 指南以了解如何使用 Vue 实现 SSR。如果应用对交互性要求不高,你还可以使用传统的后端服务器来渲染 HTML,并在客户端使用 Vue 对其进行增强。

如果你的主应用必须是 SPA,但还有其他的营销相关页面 (落地页、关于页、博客等),请单独部署这些页面!理想情况下,营销页面应该是包含尽可能少 JS 的静态 HTML,并用 SSG 方式部署
包体积与 Tree-shaking 优化
一个最有效的提升页面加载速度的方法就是压缩 JavaScript 打包产物的体积。当使用 Vue 时有下面一些办法来减小打包产物体积:

1、尽可能地采用构建步骤

    1、如果使用的是相对现代的打包工具,许多 Vue 的 API 都是可以被 tree-shake 的。举例来说,如果你根本没有使用到内置的 <Transition> 组件,它将不会被打包进入最终的产物里。Tree-shaking 也可以移除你源代码中其他未使用到的模块。

    2、当使用了构建步骤时,模板会被预编译,因此我们无须在浏览器中载入 Vue 编译器。这在同样最小化加上 gzip 优化下会相对缩小 14kb 并避免运行时的编译开销。

2、在引入新的依赖项时要小心包体积膨胀!在现实的应用中,包体积膨胀通常因为无意识地引入了过重的依赖导致的。

    1、如果使用了构建步骤,应当尽量选择提供 ES 模块格式的依赖,它们对 tree-shaking 更友好。举例来说,选择 lodash-es 比 lodash 更好。

    2、查看依赖的体积,并评估与其所提供的功能之间的性价比。如果依赖对 tree-shaking 友好,实际增加的体积大小将取决于你从它之中导入的 API。像 bundlejs.com 这样的工具可以用来做快速的检查,但是根据实际的构建设置来评估总是最准确的。

3、如果你只在渐进式增强的场景下使用 Vue,并想要避免使用构建步骤,请考虑使用 petite-vue (只有 6kb) 来代替
代码分割
代码分割是指构建工具将构建后的 JavaScript 包拆分为多个较小的,可以按需或并行加载的文件。通过适当的代码分割,页面加载时需要的功能可以立即下载,而额外的块只在需要时才加载,从而提高性能。

像 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 的懒加载。查看懒加载路由了解更多细节

更新优化

Props 稳定性
在 Vue 之中,一个子组件只会在其至少一个 props 改变时才会更新。思考以下示例:

<ListItem
  v-for="item in list"
  :id="item.id"
  :active-id="activeId" />
  
在 <ListItem> 组件中,它使用了 id 和 activeId 两个 props 来确定它是否是当前活跃的那一项。虽然这是可行的,但问题是每当 activeId 更新时,列表中的每一个 <ListItem> 都会跟着更新!

理想情况下,只有活跃状态发生改变的项才应该更新。我们可以将活跃状态比对的逻辑移入父组件来实现这一点,然后让 <ListItem> 改为接收一个 active prop

<ListItem
  v-for="item in list"
  :id="item.id"
  :active="item.id === activeId" />
  
现在,对于大多数的组件来说,activeId 改变时,它们的 active prop 都会保持不变,因此它们无需再更新。总结一下,这个技巧的核心思想就是让传给子组件的 props 尽量保持稳定
v-once
v-once 是一个内置的指令,可以用来渲染依赖运行时数据但无需再更新的内容。它的整个子树都会在未来的更新中被跳过。查看它的 API 参考手册可以了解更多细节
v-memo
v-memo 是一个内置指令,可以用来有条件地跳过某些大型子树或者 v-for 列表的更新。查看它的 API 参考手册可以了解更多细节

通用优化

大型虚拟列表
所有的前端应用中最常见的性能问题就是渲染大型列表。无论一个框架性能有多好,渲染成千上万个列表项都会变得很慢,因为浏览器需要处理大量的 DOM 节点。

但是,我们并不需要立刻渲染出全部的列表。在大多数场景中,用户的屏幕尺寸只会展示这个巨大列表中的一小部分。我们可以通过列表虚拟化来提升性能,这项技术使我们只需要渲染用户视口中能看到的部分。

要实现列表虚拟化并不简单,幸运的是,你可以直接使用现有的社区库:

1、vue-virtual-scroller

2、vue-virtual-scroll-grid

3、vueuc/VVirtualList
减少大型不可变数据的响应性开销
Vue 的响应性系统默认是深度的。虽然这让状态管理变得更直观,但在数据量巨大时,深度响应性也会导致不小的性能负担,因为每个属性访问都将触发代理的依赖追踪。好在这种性能负担通常这只有在处理超大型数组或层级很深的对象时,例如一次渲染需要访问 100,000+ 个属性时,才会变得比较明显。因此,它只会影响少数特定的场景。

Vue 确实也为此提供了一种解决方案,通过使用 shallowRef() 和 shallowReactive() 来绕开深度响应。浅层式 API 创建的状态只在其顶层是响应式的,对所有深层的对象不会做任何处理。这使得对深层级属性的访问变得更快,但代价是,我们现在必须将所有深层级对象视为不可变的,并且只能通过替换整个根状态来触发更新

const shallowArray = shallowRef([
  /* 巨大的列表,里面包含深层的对象 */
])

// 这不会触发更新...
shallowArray.value.push(newObject)
// 这才会触发更新
shallowArray.value = [...shallowArray.value, newObject]

// 这不会触发更新...
shallowArray.value[0].foo = 1
// 这才会触发更新
shallowArray.value = [
  {
    ...shallowArray.value[0],
    foo: 1
  },
  ...shallowArray.value.slice(1)
]
避免不必要的组件抽象
有些时候我们会去创建无渲染组件或高阶组件 (用来渲染具有额外 props 的其他组件) 来实现更好的抽象或代码组织。虽然这并没有什么问题,但请记住,组件实例比普通 DOM 节点要昂贵得多,而且为了逻辑抽象创建太多组件实例将会导致性能损失。

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

补充

无渲染组件

一些组件可能只包括了逻辑而不需要自己渲染内容,视图输出通过作用域插槽全权交给了消费者组件。我们将这种类型的组件称为无渲染组件

<MouseTracker v-slot="{ x, y }">
  Mouse is at: {{ x }}, {{ y }}
</MouseTracker>

标签:vue,渲染,性能,Vue,组件,页面,优化,第三十八,加载
From: https://www.cnblogs.com/caix-1987/p/17288309.html

相关文章

  • 第三十九篇 vue - 最佳实践 - 安全
    报告漏洞虽然很少发现新的漏洞,但我们仍建议始终使用最新版本的Vue及其官方配套库,以确保你的应用尽可能地安全。首要规则:不要使用无法信赖的模板使用Vue时最基本的安全规则就是不要将无法信赖的内容作为你的组件模板。使用无法信赖的模板相当于允许任意的JavaScript在你......
  • Redis 在 vivo 推送平台的应用与优化实践
    一、推送平台特点vivo推送平台是vivo公司向开发者提供的消息推送服务,通过在云端与客户端之间建立一条稳定、可靠的长连接,为开发者提供向客户端应用实时推送消息的服务,支持百亿级的通知/消息推送,秒级触达移动用户。推送平台的特点是并发高、消息量大、送达及时性较高。目前现状最高......
  • Nginx——Nginx生产环境压测与性能优化实战
    摘要nginx的主要作用有三个方面:1、作为Web服务器;2、负载均衡服务器;3、邮件代理服务器等三个方面。其特点是占有内存少,并发能力强,给使用者带来了很多的便利。nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like协议下发行。但是在日常的工作......
  • case的穿透优化
    importjava.util.Scanner;publicclasspenetrate{publicstaticvoidmain(String[]args){}publicstaticvoidswitchTest1(){//键盘录入一个数值,其中1-5表示工作日,6-7表示休息日Scannersc=newScanner(System.in);System.out......
  • Redis 内存优化在 vivo 的探索与实践
    作者:vivo互联网服务器团队-TangWenjian一、背景使用过Redis的同学应该都知道,它基于键值对(key-value)的内存数据库,所有数据存放在内存中,内存在Redis中扮演一个核心角色,所有的操作都是围绕它进行。我们在实际维护过程中经常会被问到如下问题,比如数据怎么存储在Redis里面能......
  • vue数组和对象进行 watch 和 watchEffect 对比
    constarr1=ref([]);constarr2=reactive([]);constobj1=ref({});constobj2=reactive({});watchEffect(()=>{console.log("watchEffectarr1",arr1.value);console.log("watchEffectarr2",arr2)......
  • 超详细!新手如何创建一个Vue项目
    目录一、在官网下载Vue.js二、使用<script>标签直接引入本地的vue.js三、使用CDN引入Vue.js四、验证是否安装成功五、安装VueDevtools浏览器调试插件不同浏览器导入方法本篇仅以HBuilderX为例,其余开发软件同样适用这里两种方法,使用<script>标签直接引入本地的vue.js或使用CDN......
  • 如何在vue3获取 DOM 元素
    获取dom的ref元素名称,要对应暴露的名称,不然会出现无效的dom报错,也就是拿到的是null在setup中,使用ref(null)获取dom不能直接在setup里面拿到dom的值,因为setup对应的生命周期是created,所以必须在后续的生命周期钩子里面拿到,比如onMounted注意:ref不要加冒号,直接写dom元素名称......
  • vue引入粒子背景图效果
    安装依赖npminstallvue-particles--save-devmain.jsimportVueParticlesfrom'vue-particles'Vue.use(VueParticles)template  <vue-particles     color="#409EFF"     :particleOpacity="0.7"     :parti......
  • Vue3——使用deep进行样式穿透的时候发出v-deep警告
    前言其实只是一个警告,如果你不在意也是可以的,不过有点强迫症就按着提示说的改了,然后又去官网看了下对应的文档;!>::v-deepusageasacombinatorhasbeendeprecated.Use:deep()instead.这里没啥好说的,因为Vue3的文档中有对应的解释组件作用域CSS了,而且就算不看文档根据提......