# Vue性能优化(超级详细版)

Vue性能优化详细版

1. 前言

1.1 为什么需要性能优化
  • 为什么需要性能优化:
    • 用户体验:优化性能可以提升用户体验,降低加载时间和响应时间,让用户更快地看到页面内容。
    • SEO优化:搜索引擎更喜欢快速响应的网站,优化性能可以提高网站的排名。
    • 节约成本:优化性能可以减少服务器负载和带宽使用,节约成本。

1.2 性能优化的重要性- 性能优化可以提升用户体验,减少用户等待时间,提高用户满意度。

  • 性能优化可以降低服务器负载,减少服务器资源消耗,提高网站的可扩展性和稳定性。
  • 性能优化可以提高网站的SEO排名,因为搜索引擎更喜欢快速加载的网站。
  • 性能优化可以提高开发效率,因为优化后的代码更易于维护和扩展。

2. 优化思路

2.1 减少HTTP请求

  • 合并文件:将多个文件合并为一个文件,减少HTTP请求次数。
  • 压缩文件:将文件进行压缩,减小文件大小,减少HTTP请求时间。
  • 使用CDN:使用CDN加速服务,减少服务器的请求压力,提高页面加载速度。
  • 按需加载:将页面分为多个模块,按需加载,减少不必要的请求和页面加载时间。
  • 懒加载:对于图片等资源,采用懒加载的方式,当用户需要查看时再加载,减少页面加载时间。
  • 预加载:对于一些重要资源,采用预加载的方式,提前加载,提高用户体验。
  • 使用WebP格式:WebP格式的图片比JPEG和PNG格式的图片更小,加载速度更快,可以减少HTTP请求时间。
  • 使用字体图标:使用字体图标代替图片,减少HTTP请求次数和文件大小。
  • 使用缓存:合理使用浏览器缓存和服务器缓存,减少HTTP请求次数和请求时间。
方法 描述
合并文件 将多个文件合并为一个文件,减少HTTP请求次数。
压缩文件 将文件进行压缩,减小文件大小,减少HTTP请求时间。
使用CDN 使用CDN加速服务,减少服务器的请求压力,提高页面加载速度。
按需加载 将页面分为多个模块,按需加载,减少不必要的请求和页面加载时间。
懒加载 对于图片等资源,采用懒加载的方式,当用户需要查看时再加载,减少页面加载时间。
预加载 对于一些重要资源,采用预加载的方式,提前加载,提高用户体验。
使用WebP格式 WebP格式的图片比JPEG和PNG格式的图片更小,加载速度更快,可以减少HTTP请求时间。
使用字体图标 使用字体图标代替图片,减少HTTP请求次数和文件大小。
使用缓存 合理使用浏览器缓存和服务器缓存,减少HTTP请求次数和请求时间。

2.2 代码优化

  • 减少不必要的计算和操作
  • 避免不必要的计算和操作,例如在模板中使用三元表达式,会多次计算同一个表达式,可以将其提取为计算属性
  • 避免在模板中使用大量的过滤器,过滤器会在每次渲染时都执行一次,可以考虑将过滤器的功能提取为计算属性或方法
  • 合理使用v-if和v-show
    • v-if在条件不满足时会销毁元素及其事件监听器和子组件,可以减少不必要的性能开销,但是频繁切换v-if会造成DOM频繁销毁和重建,可以考虑使用v-show代替
    • v-show只是简单的切换元素的display属性,不会销毁元素及其事件监听器和子组件,但是在初始渲染时会有一定的性能开销,当需要频繁切换元素的显示状态时,可以使用v-show代替v-if
  • 合理使用key
    • 在使用v-for渲染列表时,为每个元素添加一个唯一的key,可以帮助Vue跟踪元素的状态,减少不必要的DOM操作
  • 使用异步组件
    • 将页面按需加载可以减少初始渲染时的性能开销,可以使用Vue的异步组件功能,将页面按需加载
  • 使用keep-alive缓存组件
    • 使用keep-alive可以缓存已经渲染过的组件,当组件被切换时,可以直接从缓存中读取,减少不必要的性能开销
  • 使用懒加载
    • 当页面中存在大量图片时,可以使用懒加载的方式,将页面中的图片延迟加载,减少初始渲染时的性能开销
  • 使用CDN加速
    • 将静态资源(例如Vue、ElementUI等库文件)上传到CDN服务器,可以减少网络请求时的延迟,加快页面加载速度
  • 优化webpack配置
    • 在webpack配置中,可以使用Tree Shaking、Code Splitting等技术,减少打包后的文件体积,加快页面加载速度
    • 使用webpack-bundle-analyzer等工具,分析打包后的文件,找出体积较大的文件,进行优化

2.2.1 代码分割

  • 代码分割可以将代码按照不同的逻辑或业务分割成不同的模块,从而实现按需加载,减少页面加载时间。在Vue中,可以使用以下方式进行代码分割:

  • 使用Vue异步组件:将组件定义为函数返回一个Promise对象,在需要的时候再加载组件。

    Vue.component('async-component', () => import('./AsyncComponent.vue'));
    
  • 使用Webpack的代码分割功能:在Webpack配置文件中配置optimization.splitChunks进行代码分割。

    optimization: {
      splitChunks: {
        chunks: 'all'
      }
    }
    
  • 代码分割实例:

    • 在项目中,有一个比较大的组件需要加载,但是这个组件并不是每个页面都需要用到。在使用Vue异步组件进行代码分割之前,每次进入页面都需要加载这个组件,导致页面加载时间过长。使用Vue异步组件进行代码分割后,只有在需要用到这个组件的时候才会进行加载,从而减少了页面加载时间。

    • 在项目中,有多个页面都需要使用到一个公共的模块,但是这个模块比较大,每个页面都将这个模块打包进去会导致打包后的文件过大。使用Webpack的代码分割功能进行代码分割后,公共的模块只会被打包一次,从而减小了打包后文件的大小。

2.2.2 懒加载

  • 懒加载是将某些组件或资源推迟到实际需要的时候再加载,可以有效减少首屏加载时的资源压力。

  • 可以使用 Vue.lazy() 方法实现懒加载,也可以使用第三方库如 vue-lazyload

  • 示例代码:

    <template>
      <div>
        <img v-lazy="imgUrl">
      div>
    template>
    
    <script>
    export default {
      data() {
        return {
          imgUrl: 'https://example.com/image.jpg'
        }
      }
    }
    script>
    

2.2.3 Tree Shaking (实用)

- Tree Shaking是什么?
  • Tree Shaking是指在打包过程中,去除没有使用过的代码,只保留用到的代码,从而减小打包后的文件体积。
  • 如何使用Tree Shaking?
    • 在webpack中,可以通过在配置文件中设置optimization.minimize为true来开启Tree Shaking。
    • 在代码中,可以使用ES6的import语法来引入需要的模块,避免使用require或者import * as的方式引入整个模块。
  • 示例:
    • 假设有一个工具库utils.js,其中包含了add、sub、mul、div四个函数,我们只需要使用add和sub函数,可以这样引入:
      import { add, sub } from 'utils.js'
      
    • 在打包过程中,只有add和sub函数会被保留,mul和div函数会被去除。

2.2.4 代码压缩

  • 使用Webpack的UglifyJsPlugin插件进行代码压缩
  • 将不必要的代码进行删除和优化,如未使用的变量、函数等
  • 使用Tree shaking技术去除未引用的代码
  • 将常量提取出来,避免重复定义,例如使用webpack的DefinePlugin插件将常量定义为全局变量
  • 使用CDN引入第三方库,避免将其打包进项目中
  • 避免使用eval和with等语法,这些语法会导致代码难以压缩
  • 使用Gzip进行压缩,减小文件大小,提高加载速度
  • 使用Web Workers进行代码分离,提高运行效率
  • 使用异步加载组件,避免一次性加载所有组件,减小首屏加载时间
  • 使用路由懒加载,按需加载路由组件,提高性能

表格:

优化手段 示例
使用Webpack的UglifyJsPlugin插件进行代码压缩 optimization: {minimize: true}
使用Tree shaking技术去除未引用的代码 optimization: {usedExports: true}
将常量提取出来,避免重复定义 new webpack.DefinePlugin({ ‘process.env.NODE_ENV’: JSON.stringify(‘production’) })
使用CDN引入第三方库
使用Gzip进行压缩 server { gzip on; }
使用Web Workers进行代码分离 const worker = new Worker(‘worker.js’)
使用异步加载组件 const Foo = () => import(‘./Foo.vue’)
使用路由懒加载 const Home = () => import(‘./Home.vue’)

2.3 图片优化

  • 图片懒加载:使用vue-lazyload等插件,将图片的加载时机改为滚动到可视区域时再进行加载,减少页面初次加载时的请求量和时间。
  • 图片压缩:使用工具对图片进行压缩,减小图片文件大小,提升页面加载速度。
  • 雪碧图:将多张小图片合并成一张大图片,减少http请求次数,提升页面加载速度。
  • 响应式图片:根据不同设备的屏幕大小,加载不同尺寸的图片,减少不必要的资源浪费,提升页面加载速度。
  • CDN加速:使用CDN加速服务,将图片资源分发到全球各地的节点,提升图片加载速度,减少服务器负载。

2.3.1 图片压缩

  • 使用图片压缩工具,如TinyPNG或ImageOptim等,压缩图片大小,减少网络传输时间和页面加载时间。
  • 使用图片格式的最佳实践,如使用JPEG格式的照片,使用PNG格式的图标和透明图片等。

示例:

原图大小 压缩后大小 压缩率
1.2MB 350KB 70%

2.3.2 图片懒加载

  • 使用vue-lazyload插件实现图片懒加载
  • 将图片的src属性改为v-lazy指令
  • 可以设置loading属性来展示图片加载过程中的占位图
  • 可以设置error属性来展示图片加载失败时的占位图

示例代码:

<template>
  <div>
    <img v-for="img in imgList" :key="img.id" :src="img.src" v-lazy="img.lazySrc" />
  div>
template>

<script>
import VueLazyload from 'vue-lazyload'

export default {
  data() {
    return {
      imgList: [
        {
          id: 1,
          src: 'https://example.com/image1.jpg',
          lazySrc: 'https://example.com/image1_lazy.jpg'
        },
        {
          id: 2,
          src: 'https://example.com/image2.jpg',
          lazySrc: 'https://example.com/image2_lazy.jpg'
        },
        // ...
      ]
    }
  },
  // 注册插件
  created() {
    Vue.use(VueLazyload, {
      loading: 'https://example.com/loading.gif',
      error: 'https://example.com/error.jpg'
    })
  }
}
script>

2.4 数据优化

  • 避免不必要的数据响应式化,可以使用Object.freeze()冻结数据对象,提高渲染性能。
// 在数据不需要响应式化时使用Object.freeze()
export default {
  data() {
    return {
      // 不需要响应式化的数据
      list: Object.freeze(['apple', 'banana', 'orange'])
    }
  }
}
  • 合理使用计算属性和缓存,避免重复计算。

    
    <template>
      <div>
        <p>商品数量:{{ count }}p>
        <p>商品总价:{{ totalPrice }}p>
      div>
    template>
    
    <script>
    export default {
      data() {
        return {
          goodsList: [
            { name: 'apple', price: 5, count: 2 },
            { name: 'banana', price: 3, count: 3 },
            { name: 'orange', price: 2, count: 4 }
          ]
        }
      },
      computed: {
        count() {
          // 计算商品数量
          return this.goodsList.reduce((sum, item) => sum + item.count, 0)
        },
        totalPrice() {
          // 计算商品总价
          return this.goodsList.reduce((sum, item) => sum + item.price * item.count, 0)
        }
      }
    }
    script>
    
    
    <template>
      <div>
        <button @click="addCount">点击增加button>
        <p>计数器:{{ count }}p>
      div>
    template>
    
    <script>
    export default {
      data() {
        return {
          count: 0
        }
      },
      methods: {
        addCount() {
          // 点击按钮增加计数器
          this.count++
        }
      },
      computed: {
        // 缓存计数器的值
        cachedCount() {
          return this.count
        }
      }
    }
    script>
    
  • 使用v-if和v-show合理控制组件的显示和隐藏。

    
    <template>
      <div>
        <button @click="toggle">点击切换button>
        <p v-if="show">显示内容p>
      div>
    template>
    
    <script>
    export default {
      data() {
        return {
          show: false
        }
      },
      methods: {
        toggle() {
          // 点击按钮切换show的值
          this.show = !this.show
        }
      }
    }
    script>
    
    
    <template>
      <div>
        <button @click="toggle">点击切换button>
        <p v-show="show">显示内容p>
      div>
    template>
    
    <script>
    export default {
      data() {
        return {
          show: false
        }
      },
      methods: {
        toggle() {
          // 点击按钮切换show的值
          this.show = !this.show
        }
      }
    }
    script>
    
  • 使用key值避免不必要的组件销毁和重建。

    <template>
      <div>
        <button @click="toggle">点击切换button>
        <child-component :key="show">child-component>
      div>
    template>
    
    <script>
    import ChildComponent from './ChildComponent.vue'
    
    export default {
      components: {
        ChildComponent
      },
      data() {
        return {
          show: false
        }
      },
      methods: {
        toggle() {
          // 点击按钮切换show的值
          this.show = !this.show
        }
      }
    }
    script>
    

2.4.1 使用缓存

  • 使用缓存:
  • 对于频繁使用的组件或数据,可以使用缓存来减少重复渲染和请求。
  • 可以使用Vue提供的keep-alive组件对组件进行缓存。
  • 可以使用浏览器提供的缓存机制对请求的数据进行缓存,减少重复请求。
  • 可以使用第三方库如lru-cache等进行数据缓存。

2.4.2 数据分页

  • 在使用分页组件时,应该避免将所有数据都一次性加载出来,而是应该采用分页的方式进行数据加载,减轻页面的渲染压力。
  • 可以使用第三方的分页插件,如Element UI的分页组件,也可以自己实现分页逻辑。
  • 在进行数据分页时,应该根据实际情况设置每页显示的数据量和总数据量,以达到最优的分页效果。
  • 可以使用懒加载技术,在用户滚动页面时再进行数据加载,减少页面的初始加载时间和渲染压力。
  • 可以使用虚拟滚动技术,将页面上不可见的部分进行虚拟化处理,减少页面的渲染压力,提高页面的渲染性能。
  • 可以使用表格的分页功能,将数据分页展示在表格中,同时提供搜索和筛选功能,方便用户查找和使用。

2.4.3 数据预加载

  • 在需要使用数据的组件中,提前预加载所需数据,避免在组件渲染时才发起请求,从而提高页面响应速度。
  • 可以使用Vue的beforeRouteEnter钩子函数,在路由进入组件前预加载数据。
  • 也可以在组件的created生命周期钩子函数中使用异步请求加载数据,并使用v-if指令控制组件的显示,避免页面渲染时出现空白的情况。
  • 可以使用Vue的keep-alive组件缓存组件的状态,避免每次进入组件都需要重新加载数据,提高页面加载速度。使用activated生命周期钩子函数在组件被激活时重新加载数据。

表格:

方式 优点 缺点
beforeRouteEnter 可以在路由进入组件前预加载数据 只能在路由进入组件前使用,无法在组件内部控制
created + v-if 可以在组件的created生命周期钩子函数中预加载数据,并使用v-if指令控制组件的显示 页面渲染时可能出现空白的情况
keep-alive + activated 可以缓存组件的状态,避免每次进入组件都需要重新加载数据 只有在组件被激活时才会重新加载数据

2.5 服务端优化

  • 使用CDN加速静态资源的访问,减轻服务器负担
  • 对于频繁请求的接口,使用缓存技术,减少服务器压力
  • 合理使用HTTP缓存,减少重复请求
  • 对于大量并发请求,考虑使用负载均衡技术,分流请求
  • 使用异步请求技术,减少同步请求对服务器的占用
  • 数据库优化:合理设计数据库表结构,使用索引等技术提高查询效率
  • 使用缓存技术,减少数据库查询次数
  • 合理使用数据库连接池,避免频繁创建和销毁连接
  • 使用NoSQL等技术,提高数据读写效率
  • 对于大量日志输出,使用日志收集和分析工具,避免对服务器性能的影响。

2.5.1 使用CDN

  • 使用CDN加速静态资源加载,例如:
  • 在vue.config.js中配置:
    module.exports = {
      //...
      configureWebpack: {
        externals: {
          'vue': 'Vue',
          'vue-router': 'VueRouter',
          'vuex': 'Vuex',
          'axios': 'axios',
          'element-ui': 'ELEMENT',
        }
      }
    }
    
  • 在index.html中引入CDN链接:
    DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width,initial-scale=1.0">
      <title>My Apptitle>
      <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    head>
    <body>
      <noscript>
        <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.strong>
      noscript>
      <div id="app">div>
      
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
      <script src="https://cdn.jsdelivr.net/npm/vue-router/dist/vue-router.js">script>
      <script src="https://cdn.jsdelivr.net/npm/vuex/dist/vuex.js">script>
      <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js">script>
      <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
      <script src="https://unpkg.com/element-ui/lib/index.js">script>
    body>
    html>
    

2.5.2 服务器缓存

  • 服务器缓存可以减少服务器的请求次数,提高页面的响应速度。
  • 可以使用浏览器缓存和服务端缓存两种方式。
  • 浏览器缓存:在HTTP响应头中设置缓存策略,让浏览器缓存静态资源,减少请求次数。
  • 服务端缓存:可以使用Redis等缓存工具,将经常使用的数据缓存到内存中,减少数据库查询次数。

2.5.3 服务器压缩- 服务器压缩可以减少传输文件的大小,提高页面加载速度。

  • 使用Gzip压缩服务器响应的文件,可以减少文件大小,提高页面加载速度。
  • 在Nginx中开启Gzip压缩:
    gzip on;
    gzip_types text/plain application/xml text/css application/javascript;
    
  • 在Apache中开启Gzip压缩:
    <IfModule mod_deflate.c>
        AddOutputFilterByType DEFLATE text/plain
        AddOutputFilterByType DEFLATE text/html
        AddOutputFilterByType DEFLATE text/xml
        AddOutputFilterByType DEFLATE text/css
        AddOutputFilterByType DEFLATE application/xml
        AddOutputFilterByType DEFLATE application/xhtml+xml
        AddOutputFilterByType DEFLATE application/rss+xml
        AddOutputFilterByType DEFLATE application/javascript
        AddOutputFilterByType DEFLATE application/x-javascript
    </IfModule>
    
  • 使用CDN加速,CDN服务商会自动帮助压缩文件。

3. 优化实践

3.1 减少HTTP请求的实践

  • 通过使用WebPack的code-splitting特性,将Vue组件按需引入,减少首屏加载时间。
  • 使用Vue的异步组件,实现按需加载,减少页面首屏加载时间。
  • 使用Vue的keep-alive组件,缓存组件状态,避免重复渲染。
  • 使用CDN加速静态资源,减少HTTP请求时间。
  • 将小图片转为base64编码,减少HTTP请求。
  • 使用CSS Sprites技术,减少HTTP请求。
  • 使用HTTP缓存,减少HTTP请求。
  • 使用HTTP2协议,减少HTTP请求。

3.2 代码优化的实践

- 3.2 代码优化的实践
  • 合理使用v-if和v-show
    • 当需要频繁切换显示和隐藏时,使用v-show
    • 当需要条件渲染时,使用v-if
  • 避免使用复杂表达式
    • 将复杂表达式拆分为多个简单表达式
    • 使用computed属性或过滤器处理复杂逻辑
  • 避免频繁操作DOM
    • 尽可能减少DOM操作次数
    • 对于需要频繁操作的元素,使用v-for的key属性优化
  • 合理使用异步组件和按需加载
    • 将页面划分为多个组件,按需加载
    • 对于比较大的组件,使用异步组件
  • 减少数据监听
    • 对于不需要响应式的数据,使用Object.freeze()冻结对象
    • 对于需要响应式的数据,使用深度监听或手动触发更新
  • 使用CDN加速
    • 将静态资源部署到CDN上,加速访问速度
  • 优化图片
    • 压缩图片大小,减少加载时间
    • 使用webp格式,提高图片加载速度

3.3 图片优化的实践

  • 使用CSS Sprites技术将多个小图片合成一张大图,减少HTTP请求次数
  • 使用WebP格式代替JPEG或PNG格式,可以大幅度减小图片大小,提升加载速度
  • 使用lazyload技术,只有当图片进入可视区域才进行加载,减少不必要的网络请求
  • 对于大图,可以使用图片压缩工具进行压缩,减小图片大小
  • 针对移动端,可以使用srcset和picture标签进行响应式图片处理,提升移动端的加载速度
  • 对于需要动态生成的图片,可以使用canvas或SVG代替传统的图片格式
  • 使用CDN加速图片加载,提升用户体验

表格示例:

技术 描述
CSS Sprites 将多个小图片合成一张大图,减少HTTP请求次数
WebP 一种图片格式,可以大幅度减小图片大小,提升加载速度
lazyload 只有当图片进入可视区域才进行加载,减少不必要的网络请求
图片压缩工具 对于大图,可以使用图片压缩工具进行压缩,减小图片大小
响应式图片处理 使用srcset和picture标签进行响应式图片处理,提升移动端的加载速度
canvas和SVG 对于需要动态生成的图片,可以使用canvas或SVG代替传统的图片格式
CDN 使用CDN加速图片加载,提升用户体验

3.4 数据优化的实践

  • 避免频繁的数据更新,尽可能减少数据的双向绑定
  • 使用v-if和v-show合理控制组件的渲染
  • 合理使用computed属性和watcher监听数据变化
  • 对于列表数据,使用v-for的key属性进行优化
  • 使用懒加载和分页加载大量数据
  • 对于复杂的数据操作,使用Web Worker进行异步处理
  • 使用immutable.js等数据不可变库进行数据管理
  • 使用localStorage或IndexedDB等本地存储技术缓存数据
  • 使用CDN加速静态资源的加载
  • 对于大量图片资源,使用懒加载或预加载技术
  • 使用服务端渲染(SSR)技术减少客户端渲染压力
  • 使用缓存策略和CDN加速技术优化API请求的响应速度
优化手段 实例
避免频繁的数据更新 合并多个数据更新操作为一次更新
使用v-if和v-show合理控制组件的渲染 对于不常用的组件使用v-show代替v-if
使用懒加载和分页加载大量数据 对于列表数据使用分页加载或滚动加载
使用localStorage或IndexedDB等本地存储技术缓存数据 对于静态数据使用localStorage进行缓存

3.5 服务端优化的实践- 服务端渲染(SSR):使用vue-server-renderer将vue组件在服务端渲染成HTML字符串,减少浏览器的渲染压力,提升首屏渲染速度。

  • 启用gzip压缩:对于静态资源如js、css、图片等启用gzip压缩,减少网络传输时间,提升加载速度。
  • 使用CDN加速:将静态资源托管到CDN上,利用CDN的分布式节点缓存,加速资源的加载速度。
  • 优化数据库查询:避免一次性查询大量数据,使用分页、缓存等技术来优化数据库查询,减少数据库的压力,提升响应速度。
  • 优化服务器配置:根据服务器的硬件配置和应用的特点,合理配置服务器参数,如最大连接数、内存大小等,提升服务器的性能。

4. 总结

4.1 性能优化的重要性再强调

- 4.1 性能优化的重要性再强调:
  • 在实际项目中,性能优化是非常重要的,可以提高用户的体验,减少用户的等待时间,提高网站的转化率。
  • 通过使用Vue提供的性能优化方法,如异步组件、keep-alive、v-if/v-show等,可以使页面加载速度更快,响应更迅速,提高用户满意度。
  • 此外,还可以通过Webpack等构建工具的优化,如代码分割、懒加载等,进一步提高页面的性能表现。

4.2 性能优化的未来发展趋势

  • 使用WebAssembly来提高性能
  • 使用Service Worker来优化缓存
  • 使用HTTP/2来提高网络性能
  • 使用PWA技术来提高用户体验
  • 使用SSR技术来提高首屏渲染速度
  • 使用Webpack 5等新工具来提高打包速度和优化代码
  • 使用更多的前端性能监控工具来发现性能问题并解决。

你可能感兴趣的:(vue.js,性能优化,前端)