vue前端项目优化(编译速度、打包体积、性能)

677 阅读10分钟

一、前言

相信大家经过一段时间的工作,经历了一些项目之后,总会遇到一些项目当中的槽点,自己多多少少对项目优化有一些认识和想法。这里主要从编译速度、性能优化、打包体积三个大的方面,结合自己的实践,说一说自己对前端项目优化的理解。 如有错误,欢迎各位大佬指正,发表一下大佬们对性能优化的一些见解,相互学习,共同进步 。

二、编译速度优化

1.使用缓存

  • 在webpack3中为了提高构建速度,我们往往会用到 DllPlugin 和 DllReferencePlugin 插件,但是配置复杂,更新文件还需要手动重新生成dll,比较繁琐。还有一种autodll-webpack-plugin插件会好用一些。
  • 在webpack4之后可以使用HardSourceWebpackPlugin插件,它通过在磁盘中设置缓存来提升编译加载速度,第一次正常编译并缓存,第二次有缓存后能减少80%-90%的时间,需要安装插件后使用。
  • webpack5主要使用内置的cache配置。

1.1 autodll-webpack-plugin插件

autodll-webpack-plugin插件可以将项目中的第三方库(如lodash、moment等)单独打包成一个DLL文件,从而减少主文件的体积,提高编译速度。 运行webpack命令进行构建,生成的DLL文件会存放在dist目录下。通过使用autodll-webpack-plugin插件,可以有效地优化Vue项目,提高编译速度和运行效率。

  • 安装

     npm install autodll-webpack-plugin --save-dev
    
  • 引入

     const AutoDllPlugin = require('autodll-webpack-plugin');
    
  • 配置

     module.exports = {
       // ...其他配置
       plugins: [
         // ...其他插件
         new AutoDllPlugin({
           inject: true, // 自动注入生成的DLL文件到HTML中
           filename: '[name].dll.js', // DLL文件名格式
           entry: {
             vendor: ['vue', 'vue-router', 'vuex'] // 需要单独打包的第三方库
           }
         })
       ]
     };
     ​
    

1.2 HardSourceWebpackPlugin插件

HardSourceWebpackPlugin是一个用于优化Webpack构建速度的插件。它可以为模块代码创建内存缓存,这样在每次构建时,只需要处理发生更改的模块,而不是重新处理所有模块。 为了查看结果,需要使用此插件运行 webpack 两次:第一次构建将花费正常的时间。第二个构建速度将明显加快。

  • 安装

     npm install hard-source-webpack-plugin --save-dev
    
  • 引入

     const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
    
  • 配置

     module.exports = {
         // ...
         configureWebpack: smp.wrap({
             plugins: [
               // 为模块提供中间缓存,缓存路径是:node_modules/.cache/hard-source
               new HardSourceWebpackPlugin()
             ]
         })
         // ...
     }
    
  • 注意:这里有另一个插件 speed-measure-webpack-plugin插件,作用是分析构建时各模块耗时,不能与hard-source-webpack-plugin一起使用

1.3 webpack5配置cache

webpack5 内置了 cache 缓存机制。直接配置即可。cache 会在开发模式下被设置成 type: memory 而且会在生产模式把cache 给禁用掉。

  • 配置

     // webpack.config.js 或 vue.config.js
     const path = require('path')
     ​
     module.exports = {
         transpileDependencies: true,
         configureWebpack: {
             cache: {
                 type: 'filesystem', // 设置缓存类型为文件系统
                 cacheDirectory: path.resolve(__dirname, '.webpack_cache') // 设置缓存目录(根路径下)
                 // cacheDirectory: path.join(__dirname, 'node_modules/.cache/webpack_cache') // 设置缓存目录(node_modules/.cache路径下)
             }
         }
     }
     ​
    

2.多线程打包

2.1 thread-loader

thread-loader 是一个 Webpack 的 loader,它可以将一些开销较大的工作放到 worker 池中,并在 worker 池中执行,以提高构建速度。 注意,thread-loader 并不是适用于所有场景的,它只对一些开销较大的任务有效。如果任务本身就非常快速并且非常简单,则使用 thread-loader 可能会比直接在主线程中执行更慢。因此可以使用上文提到的speed-measure-webpack-plugin插件对构建时各模块的耗时进行分析,对开销较大的模块使用thread-loader以提高构建速度。

  • 安装

     npm install thread-loader --save-dev
    
  • 使用示例(具体配置写法根据项目不同写法各异)

     // webpack.config.js
     module.exports = {
       module: {
         rules: [
           {
             test: /.js$/,
             include: path.resolve('src'),
             exclude: /node_modules/,
             use: [
               'thread-loader', // 将后续 loader 放在 worker 池中执行耗时的 loader (例如 babel-loader)
               'babel-loader'
             ]
           }
         ]
       }
     }
     ​
     // vue.config.js
     module.exports = {
       // ...
       configureWebpack: {
         module: {
           rules: [
             {
               test: /.js$/,
               include: path.resolve('src'),
               exclude: /node_modules/,
               use: [
                 'thread-loader', // 将后续 loader 放在 worker 池中执行耗时的 loader (例如 babel-loader)
                 'babel-loader'
               ]
             }
           ]
         }
       }
     }
    

2.2 HappyPack

HappyPack 是一个用于将 Webpack 进行多线程编译的工具,它能够将一个复杂的 Loader 或者 Plugin 任务分解成多个子进程并行执行,以此来加快构建速度。

  • 安装

     npm install happypack --save-dev
    
  • 配置

     const HappyPack = require('happypack');
     ​
     module.exports = {
       // ...
       module: {
         rules: [
           {
             test: /.js$/,
             exclude: /node_modules/,
             use: 'happypack/loader?id=js'
           }
         ]
       },
       plugins: [
         new HappyPack({
           id: 'js',
           threads: 4,
           loaders: ['babel-loader']
         })
       ],
       // ...
     };
    

3. 开启热更新/热重载

  • 热更新(Hot Update):在代码文件被修改后,自动编译出新的代码,并将新代码注入到浏览器运行的 JavaScript 中。热更新并没有重新加载页面,而是更新了部分改动的内容,保留了页面的状态信息,因此可以保持用户的操作状态。
  • 热重载(Hot Reload):在代码文件被修改后,以最快的速度重新编译、打包,并刷新浏览器窗口。相比于热更新,热重载不仅更新了 JavaScript 代码,还重新渲染了整个页面,因此会有一短暂的闪屏,更适用于 UI 相关的修改。
  • 模块热替换(Hot Module Replacement):类似于热更新,但是只替换变化的部分,不会重载整个模块或者应用程序,因此速度更快,体验更好。模块热替换不仅适用于 JavaScript 模块,还可以用于 CSS、图片等资源的替换。

3.1 HotModuleReplacementPlugin 插件

HotModuleReplacementPlugin 是 Webpack 提供的一个插件,用于启用模块热替换(HMR)功能。HMR 是一种开发模式,它可以在不刷新整个页面的情况下,只更新修改过的部分,提高开发效率。 通过上述配置,就可以开启 Webpack 的模块热替换功能,使得在开发过程中能够实时预览修改的效果,提高开发效率。需要注意的是,HMR 功能只适用于开发环境,在生产环境中不应该使用。

  • 配置

     const webpack = require('webpack');
     ​
     module.exports = {
       // ...
       mode: 'development',
       devtool: 'eval-source-map', // 使用 source-map 方便调试
       devServer: {
         port: 8080,
         hot: true, // 开启 HMR 功能
         open: true // 自动打开浏览器
       },
       plugins: [
         new webpack.HotModuleReplacementPlugin() // 启用 HMR 功能
       ]
     }
    

3.2 babel-plugin-dynamic-import-node 插件

babel-plugin-dynamic-import-node 是一个 Babel 插件,用于在开发环境中动态导入模块,从而帮助 Hot Module Replacement (HMR) 更快地处理模块的更新。要使用这个插件,你需要按照以下步骤操作:

  1. 安装插件: 首先,通过 npm 安装 babel-plugin-dynamic-import-node 插件:

     npm install --save-dev babel-plugin-dynamic-import-node
    
  2. 配置 Babel: 在你的项目根目录下找到或者创建一个 Babel 配置文件(通常是 .babelrcbabel.config.js 文件),然后在 "plugins" 部分添加 'dynamic-import-node'

     {
       "plugins": ["dynamic-import-node"]
     }
    

    如果你使用的是 babel.config.js,则配置如下:

     module.exports = {
       plugins: ['dynamic-import-node'],
     }   
    
  3. 在代码中使用: 在你的代码中,你可以使用 ES2020 的动态 import() 语法来导入模块。例如:

     if (condition) {
       import('./module.js').then((module) => {
         // 使用 module
       });
     }
    
  1. Webpack 配置: 确保你的 Webpack 配置中已经启用了 HMR。具体配置参考3.1所述。

4.exclude & include

在 Vue 项目中使用 exclude 和 include 可以帮助提升编译速度,这是因为它们可以减少不必要的文件检查和编译。

exclude 和 include 是通过 webpack 的 module.rules 配置项来设置的。其中,exclude 表示排除某些目录或文件不被编译,而 include 表示包含某些目录或文件进行编译。

下面以 Vue 项目的 Babel 编译为例,介绍如何使用 exclude 和 include。

  • 安装依赖:其中,babel-loader 是用于编译 JavaScript 代码的工具,@babel/core 是 Babel 核心库,@babel/preset-env 是一种预设包,可以根据目标环境自动选择转换插件。
 npm install --save-dev babel-loader @babel/core @babel/preset-env
  • 配置 webpack.config.js:

    • 以下配置中,exclude: /node_modules/ 表示排除 node_modules 目录下的 JavaScript 文件不被编译,以提高编译速度。

       module.exports = {
         // ...其他配置
         module: {
           rules: [
             {
               test: /.js$/,
               exclude: /node_modules/,
               use: {
                 loader: 'babel-loader',
                 options: {
                   presets: ['@babel/preset-env']
                 }
               }
             }
           ]
         }
       }
      
    • 有时候,如果我们只需要编译项目中某个目录下的 JavaScript 文件,可以使用 include 来指定相应的目录。例如,我们只需要编译 src/components 目录下的 JavaScript 文件,可以将配置改为:

       module.exports = {
         // ...其他配置
         module: {
           rules: [
             {
               test: /.js$/,
               include: path.resolve(__dirname, 'src/components'),//表示只包含 src/components 目录下的 JavaScript 文件进行编译
               use: {
                 loader: 'babel-loader',
                 options: {
                   presets: ['@babel/preset-env']
                 }
               }
             }
           ]
         }
       }
      

5.提升webpack版本

升级 Webpack 版本是提高构建速度的一个重要方式,每个新版本都会带来新的优化和性能改进。

更新 Webpack 到最新版本: 首先需要确定当前使用的 Webpack 版本并检查是否需要更新,可以通过 npm 命令安装最新版本的 Webpack:

  • 检查 Webpack 相关的插件和 loader 的版本: 升级 Webpack 时,应该同时检查相关的插件和 loader 是否需要更新,需要确保其与 Webpack 的版本兼容。
  • 移除废弃的插件和 loader: 升级可能有些插件和loader 已经随着升级废弃了,因此需要移除对应的插件和 loader。

这里我在项目当中运用的时候,是将webpack版本从webpack4的低版本,升级到webpack4的最新版本;由于升级成webpack5对项目改动量太大,许多配置项还有依赖、Webpack 相关的插件和 loader 的版本都需要改变,项目为内网开发,不便于大版本升级。最后就升级到webpack4最新版本,只需要更新node_modelus相关依赖就可以了,项目编译速度也得到一定的提升。

webpack4升级到webpack5可参考文档:blog.csdn.net/m0_37937502…

三、打包体积优化

1. 分析打包结果

webpack-bundle-analyzer 是一个 Webpack 插件和命令行工具,用于分析 Webpack 的打包文件。在 Vue CLI 项目中使用它,可以帮助你理解并优化你的应用程序包的大小。

要在 Vue CLI 项目中使用 webpack-bundle-analyzer,你需要按照以下步骤操作:

  1. 安装: 首先,你需要在你的 Vue CLI 项目中安装 webpack-bundle-analyzer 插件。你可以通过运行以下命令来安装:

     npm install --save-dev webpack-bundle-analyzer 
    
  2. 配置: 接下来,你需要在你的 Webpack 配置文件中添加 webpack-bundle-analyzer 插件。对于 Vue CLI 3 项目,你可以在 vue.config.js 文件中进行配置。如果文件不存在,你需要创建它。在 vue.config.js 文件中,你可以添加以下内容:

     // javascript复制代码运行
     const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
     ​
     module.exports = {
       configureWebpack: {
         plugins: [
           new BundleAnalyzerPlugin()
         ]
       }
     };
     ​
         
    

    对于 Vue CLI 4 及更高版本的项目,你需要在 vue.config.js 文件中稍微修改配置:

     // javascript复制代码运行
     const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
     ​
     module.exports = {
       configureWebpack: {
         plugins: [
           new BundleAnalyzerPlugin()
         ]
       }
     };
    
  3. 构建: 现在,当你运行 Vue CLI 项目的构建命令时,webpack-bundle-analyzer 将会被触发。它将分析你的打包文件,并自动打开一个网页,显示各个包的大小和组成。

  4. 查看报告: Webpack Bundle Analyzer 会生成一个交互式的可视化报告,你可以在浏览器中查看。报告将展示每个包的内容,以及它们的大小。这有助于识别可以优化的地方,例如未使用的代码或过大的依赖项。

  5. 优化: 根据报告的结果,你可以采取相应的优化措施,例如移除不必要的依赖、按需导入组件或模块、使用 Tree-shaking 和 Code Splitting 等 Webpack 功能。

2.第三方库按需引入

2.1 element-ui按需引用

完整组件列表以 components.json(引用版本的)为准

  • 步骤1:安装 babel-plugin-component 插件:
 npm i babel-plugin-component -D
  • 步骤2:在babel.config.js.babelrc文件中配置:
 module.exports = {
   presets: [
     '@vue/cli-plugin-babel/preset',
     [
       '@babel/preset-env',
       {
         modules: false
       }
     ]
   ],
   plugins: [
     [
       'component',
       {
         libraryName: 'element-ui',
         styleLibraryName: 'theme-chalk'
       }
     ]
   ]
 };
  • 步骤3:创建element.js
 // element-ui 按需引入
 // 注:完整组件列表以 components.json (引用版本的)为准
 // https://github.com/ElemeFE/element/blob/master/components.json
 import {
   Pagination,
   Dialog,
   Autocomplete,
   Dropdown,
   DropdownMenu,
   DropdownItem,
   Menu,
   Submenu,
   MenuItem,
   MenuItemGroup,
   Input,
   InputNumber,
   Radio,
   RadioGroup,
   RadioButton,
   Checkbox,
   CheckboxButton,
   CheckboxGroup,
   Switch,
   Select,
   Option,
   OptionGroup,
   Button,
   ButtonGroup,
   Table,
   TableColumn,
   DatePicker,
   TimeSelect,
   TimePicker,
   Popover,
   Tooltip,
   Breadcrumb,
   BreadcrumbItem,
   Form,
   FormItem,
   Tabs,
   TabPane,
   Tag,
   Tree,
   Alert,
   Slider,
   Icon,
   Row,
   Col,
   Upload,
   Progress,
   Spinner,
   Badge,
   Card,
   Rate,
   Steps,
   Step,
   Carousel,
   Scrollbar,
   CarouselItem,
   Collapse,
   CollapseItem,
   Cascader,
   ColorPicker,
   Transfer,
   Container,
   Header,
   Aside,
   Main,
   Footer,
   Timeline,
   TimelineItem,
   Link,
   Divider,
   Image,
   Calendar,
   Backtop,
   PageHeader,
   CascaderPanel,
   Avatar,
   Drawer,
   Popconfirm,
 } from 'element-ui'
 const components = [
   Pagination,
   Dialog,
   Autocomplete,
   Dropdown,
   DropdownMenu,
   DropdownItem,
   Menu,
   Submenu,
   MenuItem,
   MenuItemGroup,
   Input,
   InputNumber,
   Radio,
   RadioGroup,
   RadioButton,
   Checkbox,
   CheckboxButton,
   CheckboxGroup,
   Switch,
   Select,
   Option,
   OptionGroup,
   Button,
   ButtonGroup,
   Table,
   TableColumn,
   DatePicker,
   TimeSelect,
   TimePicker,
   Popover,
   Tooltip,
   Breadcrumb,
   BreadcrumbItem,
   Form,
   FormItem,
   Tabs,
   TabPane,
   Tag,
   Tree,
   Alert,
   Slider,
   Icon,
   Row,
   Col,
   Upload,
   Progress,
   Spinner,
   Badge,
   Card,
   Rate,
   Steps,
   Step,
   Carousel,
   Scrollbar,
   CarouselItem,
   Collapse,
   CollapseItem,
   Cascader,
   ColorPicker,
   Transfer,
   Container,
   Header,
   Aside,
   Main,
   Footer,
   Timeline,
   TimelineItem,
   Link,
   Divider,
   Image,
   Calendar,
   Backtop,
   PageHeader,
   CascaderPanel,
   Avatar,
   Drawer,
   Popconfirm,
 ]
 const element = {
   install: (Vue) => {
     components.forEach((component) => {
       Vue.component(component.name, component)
     })
     // 单独设置
     Vue.use(Loading.directive)
     Vue.prototype.$loading = Loading.service
     Vue.prototype.$msgbox = MessageBox.methods.msgbox
     Vue.prototype.$alert = MessageBox.methods.alert
     Vue.prototype.$confirm = MessageBox.methods.confirm
     Vue.prototype.$prompt = MessageBox.methods.prompt
     Vue.prototype.$notify = Notification.methods.notify
     Vue.prototype.$message = Message.methods.message
   },
 }
 export default element
  • 步骤4:main.js引用(引用方式从引用官方组件换成引用自定义的element.js)
 // import ElementUI from 'element-ui' // 全局引用
 import ElementUI from '@/utils/element' // 按需引用
 import 'element-ui/lib/theme-chalk/index.css'
 Vue.use(ElementUI)

之后正常使用即可

2.2 echart按需引用

这里直接创建一个echart.js文件,然后在需要使用的地方引用即可, 引用方式从引用官方组件换成引用自定义的echarts.js

 // import * as echarts from 'echarts' // 全量引入
 import echarts from '@/utils/echarts' // 按需引入

echart.js文件

 // echarts 按需引入
 import * as echarts from 'echarts/core' // 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
 import { BarChart, LineChart, PieChart } from 'echarts/charts' // 引入图表类型,图表后缀都为 Chart
 import { CustomChart } from 'echarts/charts' // 自定义类型的图表
 import { 
     TitleComponent, 
     TooltipComponent, 
     GridComponent, 
     LegendComponent, 
     DatasetComponent, 
     TransformComponent, 
     DataZoomComponent 
 } from 'echarts/components' // 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
 import { LabelLayout, UniversalTransition } from 'echarts/features' // 标签自动布局、全局过渡动画等特性
 import { SVGRenderer } from 'echarts/renderers' // 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
 ​
 // 将以上引入的组件使用use()方法注册
 echarts.use([BarChart, LineChart, PieChart, CustomChart,TitleComponent, TooltipComponent, GridComponent, LegendComponent, DatasetComponent,TransformComponent,DataZoomComponent,LabelLayout, UniversalTransition,SVGRenderer])
 ​
 export default echarts // 导出
 ​

2.3 lodash按需引用

方法一:使用’lodash-es’代替’lodash’

 import { cloneDeep } from 'lodash-es' // 按需引入
 import { throttle, debounce } from 'lodash-es' // 按需引入
 // import lodash from 'lodash-es' // 全量引入

方法二:使用’lodash’时注意按需引用

 import cloneDeep from 'lodash/cloneDeep' // 按需引入
 // import lodash from 'lodash' // 全量引入

3.生产环境去掉console.log

3.1 babel-plugin-transform-remove-console插件

这是一个Babel插件,可以在构建期间删除所有console.*语句

  • 安装

     npm install --save-dev babel-plugin-transform-remove-console
    
  • 配置: babel.config.js.babelrc文件中添加以下代码

     const plugins = [];
     // remove console.* in production
     if (process.env.NODE_ENV === 'production') {
       plugins.push('transform-remove-console');
       // plugins.push(['transform-remove-console', { 'exclude': ['error', 'warn'] }]);
     }
     module.exports = {
       // ...
       plugins: plugins,
     };
    

3.2 main.js里面通过方法实现

 // main.js
 function isProduction() {
   return process.env.NODE_ENV === 'production';
 }
 ​
 if (isProduction()) {
   console.log = function () {};
 }
 ​
 // 在需要的地方调用console.log
 console.log("这是一个测试信息"); // 如果当前环境是生产环境,则不会输出任何内容

4. 合理使用source-map

productionSourceMap的作用在于定位问题,打包时会生成.map文件,在生产环境就可以在浏览器查看到输出的信息具体是在哪一行,但相应的包的体积也会变大,也会影响构建速度,将其设置为false则不生成.map文件,既可以减少包大小,也可以加密源码。

 module.exports = {
     productionSourceMap: false
 }

5. 压缩css、js、图片资源,删除无用代码

5.1 css/js压缩

  1. 安装插件
     npm install css-minimizer-webpack-plugin terser-webpack-plugin --save-dev
    
  2. 配置
     const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
     const TerserPlugin = require('terser-webpack-plugin');
     
     module.exports = {
       configureWebpack: {
         optimization: {
           minimizer: [
             new CssMinimizerPlugin(),
             new TerserPlugin()
           ]
         }
       },
       css: {
         extract: true, //将 CSS 提取到单独的文件中
         minimize: true, //启用 CSS 压缩
         sourceMap: false, //禁用 CSS source map
         loaderOptions: { //特定的加载器(如 Sass 或 Less)提供额外的配置
           sass: {
             prependData: `@import "~bootstrap/scss/functions"; @import "~bootstrap/scss/variables";`, //
           },
         },
       },
     };
    

5.2 图片资源压缩

  1. 安装loader
     npm install --save-dev image-webpack-loader
    
  2. 配置
     module.exports = {
         ...
         // 配置别名
         chainWebpack: config => {
             // 图片压缩
             config.module
                 .rule('images')
                 .exclude.add(resolve('src/assets/icons')) // 排除icons目录,这些图标已用 svg-sprite-loader 处理,打包成 svg-sprite 了
                 .end()
                 .use('url-loader')
                 .tap(options => ({
                     limit: 10240, // 稍微改大了点
                     fallback: {
                         loader: require.resolve('file-loader'),
                         options: {
                             // 在这里修改file-loader的配置
                             // 直接把outputPath的目录加上,虽然语义没分开清晰但比较简洁
                             name: 'static/img/[name].[hash:8].[ext]',
                             esModule: false, //低版本默认为false,高版本默认为true 这里为6.2.0为高本版本所以要手动设置为false
                         }
                     }
                 }))
                 .end()
                 .use('image-webpack-loader')
                 .loader('image-webpack-loader')
                 .options({
                     mozjpeg: { progressive: true, quality: 50 }, // 压缩JPEG图像
                     optipng: { enabled: true }, // 压缩PNG图像
                     pngquant: { quality: [0.5, 0.65], speed: 4 }, // 压缩PNG图像
                     gifsicle: { interlaced: false } // 压缩GIF图像
                 })
                 .end()
                 .enforce('post') // 表示先执行配置在下面那个loader,即image-webpack-loader
         },
     }
    

四、性能优化

1. 路由懒加载

路由懒加载是指在需要的时候才加载对应的路由模块,而不是在项目初始化时就加载所有的路由模块。这样可以减少初始加载时间和资源消耗,提高页面加载速度和用户体验。在 Vue 项目中,可以使用动态导入的方式来实现路由懒加载。

  • 在路由配置文件(如 router.js)中定义路由时,使用 import 函数懒加载路由组件

     import Vue from 'vue'
     import Router from 'vue-router'
     ​
     Vue.use(Router)
     ​
     const Home = () => import('./views/Home.vue')
     ​
     export default new Router({
       mode: 'history',
       base: process.env.BASE_URL,
       routes: [
         {
           path: '/',
           name: 'home',
           component: Home
         },
       ]
     })
    

2. 合理使用 watch & computed

  1. 优化 watch 的性能

    • 尽量避免在 watch 中进行异步操作,因为异步操作通常会阻塞 JS 线程,影响页面性能。如果必须进行异步操作,可以使用 vm.$nextTickPromise.then 方法,将异步操作推迟到下一次 DOM 更新时执行。
    • 在监听数组或对象等复杂数据类型时,尽量使用 deep 选项来监听其子属性的变化,而不是使用 immediate 选项来立即执行回调函数。因为 immediate 会立即执行回调函数,导致监听的数据被多次计算和渲染,影响页面性能。
    • 避免在 watch 中执行过多的计算和渲染操作,尽量将这些操作放在 computed 属性中进行处理。
  1. 优化 computed 的性能

    • 避免在 computed 中引用其他 computed,因为这样会导致多余的计算和渲染,降低页面性能。
    • 对于数据量较大或计算量较大的 computed,可以使用 lazy 选项,将其设置为惰性计算,只有在需要计算时才会重新计算。
    • 对于一些频繁变化的响应式数据,可以考虑使用 watch 来监听其变化,而不是使用 computed 来计算。

3. 合理使用防抖、节流函数

函数节流(throttle)与 函数防抖(debounce)都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象,是应对频繁触发事件的优化方案。

4. 合理使用v-if与v-show

  1. v-if

    • 作用:根据绑定的表达式的真假值来决定是否渲染 DOM 元素。当绑定的表达式为真值时,该元素会被渲染到页面中;当绑定的表达式为假值时,该元素不会被渲染到页面中,相当于从 DOM 树中移除该元素及其子元素。
    • 优点:在条件不成立时,可以减少不必要的 DOM 元素的渲染和加载,从而提高页面的加载速度和性能表现。
    • 缺点:每次切换条件,都会重新创建和销毁对应的组件或元素,因此在程序运行时可能会比 v-show 慢。
  1. v-show

    • 作用:根据绑定的表达式的真假值来控制元素的显示和隐藏。与 v-if 不同,v-show 并不会从 DOM 树中移除元素,而是通过修改其 CSS 样式来控制元素的显示和隐藏。
    • 优点:在条件不成立时,并不会从 DOM 树中移除该元素及其子元素,因此在切换条件时,可以保留该元素的状态和属性,提高页面切换的平滑度和体验。
    • 缺点:在条件不成立时,该元素仍会被加载到页面中,因此可能会增加页面的渲染和加载时间。所以,对于需要频繁切换的元素或组件,建议使用 v-show