Vue项目性能优化方案

这篇具有很好参考价值的文章主要介绍了Vue项目性能优化方案。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、代码层面的优化

 1、v-if和v-show的使用场景
 (1)v-if适用于在运行时很少改变条件,不需要频繁切换条件的场景,属于真正的条件渲染,会确保在切换过程中,元素适当的被销毁和重建,也是惰性的;
 (2)v-show适用于频繁切换条件的场景,v-show不管初始的渲染条件是什么,元素总是会被渲染,然后根据css的display属性的值去切换显示与隐藏。

2、computed和watch的使用场景
 (1)当需要进行数值计算,并且依赖于其他数据时,应该使用computed,可以利用computed的缓存特性,避免每次获取值的时候都重新计算;
 (2)当需要在数据变化时执行异步或开销较大的操作时,应该是用watch,使用watch允许我们进行异步操作,限制我们执行该操作的频率,并且在我们得到最终结果前,设置中间值,能拿到每一次的当前值和前一次的值。

 3、v-for循环遍历必须为item添加key,key不建议设置为索引,且避免在同一个元素中同时使用v-if

4、长列表性能优化
 vue会通过Object.defineProperty()对数据进行劫持,来实现响应数据的变化,但是有时候我们的组件只需要实现对数据的展示就可以了,不会有其他修改删除的操作,所以就不需要vue来劫持我们的数据,在大量数据展示的情况下,这能够很明显的减少组件初始化的时间,可以通过Object.freeze()方法来冻结一个对象,一旦被冻结的对象就不可以被修改

5、图片资源懒加载:使用vue-lazyload插件
安装:npm install vue-lazyload --save-dev
main.js引入:import VueLazyload from 'vue-lazyload'
使用:Vue.use(VueLazyload)
页面中使用,直接将img的src属性改成v-lazy:<img v-lazy="/static/img/logo.png">

6、路由懒加载:const comp = () => import('./Comp.vue')

7、第三方插件的按需引入

8、vue优化无限列表性能:使用vue-virtual-scroll-list插件
安装:npm install vue-virtual-scroll-list --save-dev
使用:<virtual-list style="height: 660px; overflow-y: auto;" :data-key="'id'" :data-sources="itemData" :data-component="itemComponent" /> (itemData:数据,itemConponent:真正展示内容的组件)

9、keep-alive的使用
利用keep-alive将不活动的组件缓存起来,在组价切换过程中,将组件的状态保存在内存中,防止重复渲染dom,减少加载时间及性能消耗,提高用户体验。

二、webpack层面的优化

1、对图片进行压缩
在 vue 项目中除了可以在 webpack.base.conf.js 中 url-loader 中设置 limit 大小来对图片处理,对小于 limit 的图片转化为 base64 格式,其余的不做操作。所以对有些较大的图片资源,在请求资源的时候,加载会很慢,我们可以用 image-webpack-loader来压缩图片;
安装:npm install image-webpack-loader --save-dev
webpack.js中配置:

{
  test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
  use:[
    {
    loader: 'url-loader',
    options: {
      limit: 10000,
      name: utils.assetsPath('img/[name].[hash:7].[ext]')
      }
    },
    {
      loader: 'image-webpack-loader',
      options: {
        bypassOnDebug: true,
      }
    }
  ]
}


2、减少es6转为es5的冗余代码
Babel插件会在es6代码转换成es5代码的时候注入一些辅助函数,例如:class HelloWebpack extends Component{...},这段代码再被转换成能正常运行的es5代码时需要以下两个辅助函数:

babel-runtime/helpers/createClass  // 用于实现 class 语法
babel-runtime/helpers/inherits  // 用于实现 extends 语法


在默认情况下,Babel会在每个输出文件中内嵌这些依赖的辅助函数代码,如果多个源代码文件都依赖于这些辅助函数,那么这些辅助函数的代码将会出现很多次,造成代码冗余,为了不然他们重复出现,可以在依赖他们时通过 require('babel-runtime/helpers/createClass')的方式导入,这样就能做到只出现一次了,babel-plugin-transform-runtime这个插件就是用来实现这个作用的,将相关的辅助函数进行替换成导入语句,从而减小babel编译出来的代码的大小;
安装:npm install babel-plugin-transform-runtime --save-dev
修改.babelrc配置文件:

"plugins": [
    "transform-runtime"
]


3、提取公共代码,业务代码和第三方库代码分开:webpack3中使用CommonsChunkPlugin插件、webpack4中使用optimization.splitChunks插件

CommonsChunkPlugin插件详细参数:
name: 给这个包含公共代码的chunk命名
filename: 命名打包后生成的js文件
minChunks: 公共代码的判断标准,某个js模块被多少个文件引入才算公共代码,默认为1,我们可以为2, 也就是说如果
一个文件被其他页面引入了超过了2次及以上,就可以认为该文件就是公用代码。
chunks: 表示需要在哪些chunk(配置中entry的每一项)里寻找公共代码进行打包,默认不设置,那么它的寻找范围为所有的chunk;

如果项目中没有把每个页面的第三方库和公共模块提取出来,则项目会存在以下问题:
a、相同的资源被重复加载,浪费客户的流量和服务器的成本
b、每个页面需要加载的资源太大,导致网页首屏加载缓慢,影响用户体验
所以我们需要将多个页面的公共代码抽离成单独的文件,来优化以上问题,webpack专门内置了用于提取多个chunk中的公共部分的插件CommonsChunkPlugin,我们在项目中CommonChunkPlugin的配置如下:

// 所有在 package.json 里面依赖的包,都会被打包进 vendor.js 这个文件中。
new webpack.optimize.CommonsChunkPlugin({
  name: 'vendor',
  minChunks: function(module, count) {
    return (
      module.resource &&
      /\.js$/.test(module.resource) &&
      module.resource.indexOf(
        path.join(__dirname, '../node_modules')
      ) === 0
    );
  }
}),
// 抽取出代码模块的映射关系
new webpack.optimize.CommonsChunkPlugin({
  name: 'manifest',
  chunks: ['vendor']
})

optimization.splitChunks参数详解:

(1)、cacheGroups:splitChunks配置的核心,对代码的拆分规则全在cacheGroups缓存组里配置,缓存组里的每一个属性都是一个配置规则,可以自己定义属性名称,属性值是一个对象,放的是对一个代码拆分规则的描述,有两个属性:name和chunks;
name:提取出来的公共模块将会以这个名称命名,可以不配置,如果不配置的话,就会生成默认的文件名
chunks:指定哪些类型的chunks参与拆分,值可以是string也可以是函数,如果是string的话,可以有三个值:all、async、initial,all代表所有模块,async代表异步加载的,initial代表初始化时就能获取的模块,如果是函数,则可以通过chunks的name属性等进行更详细的筛选

(2)、miniChunks:splitChunks是自带默认配置的,而缓存组默认会继承这些配置,其中有个miniChunks属性,它是控制每个模块什么时候被抽离出去:当模块被不同的entry引用的次数大于等于这个配置的值时,才会被抽离出去,默认值是1,也就是任何模块都会被抽离出去,(入口模块也会被webpack引入一次)

(3)、miniSize:提取的chunk的最小大小

(4)、priority:值为数值型,可以是负数,作用是当拆分组中设置多个拆分规则,且某个模块符合多个规则时,则通过优先级属性priority来决定使用哪个拆分规则,优先级高者执行

(5)、test:用于进一步控制缓存组选择的模块,可以是一个正则表达式,也可以是一个函数,可以匹配模块的绝对路径或chunk名称,匹配chunk名称时将选择chunk中所有的模块

例子:

optimization: {
    splitChunks: {
        minSize: 30,  //提取出的chunk的最小大小
        cacheGroups: {
            default: {
                name: 'common',
                chunks: 'initial',
                minChunks: 2,  //模块被引用2次以上的才抽离
                priority: -20
            },
            vendors: {  //拆分第三方库(通过npm|yarn安装的库)
                test: /[\\/]node_modules[\\/]/,
                name: 'vendor',
                chunks: 'initial',
                priority: -10
            }
        }
    }
}

4、构建结果输出分析:webpack-bundle-analyzer
webpack输出的代码可读性很差,而且文件非常大,为了简单、直观的分析输出结果,可以使用分析工具,以图形的形式将结果更直观的展示出来
安装:npm install --save-dev webpack-bundle-analyzer
webpack.config.js配置:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
plugins: [
    new BundleAnalyzerPlugin()
    ]


package.json的"scripts"中添加:

"dev": "webpack --config webpack.config.js --progress"


执行语句生成分析报告:npm run dev

5、打包去掉console.log等语句:uglifyjs-webpack-plugin
安装:npm install uglifyjs-webpack-plugin
webpack.config.js中配置:

const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
    configureWebpack: (config) => {
        if (process.env.NODE_ENV === 'production') {
            return {
                plugins: [
                    //打包环境去掉console.log
                    new UglifyJsPlugin({
                        uglifyOptions: {
                            compress: {
                                warnings: false,
                                drop_console: true,  //注释console
                                drop_debugger: true, //注释debugger
                                pure_funcs: ['console.log'], //移除console.log
                            },
                        },
                    }),
                ],
            }
        }
    }
}

三、基础的web技术优化

1、开启gzip压缩:compression-webpack-plugin
安装://新版本不太兼容,推荐这个版本
npm install compression-webpack-plugin@6.1.1 --save-dev
在webpack.config.js中使用:

const CompressionWebpackPlugin = require('compression-webpack-plugin')
new CompressionWebpackPlugin({
      filename: '[path][base].gz',
      algorithm: 'gzip',  // 压缩算法,官方默认压缩算法是gzip
      test: /\.js$|\.css$|\.html$|\.eot$|\.woff$/, // 使用gzip压缩的文件类型
      threshold: 10240,  // 以字节为单位压缩超过此大小的文件,默认是10240
      minRatio: 0.8,  // 最小压缩比率,默认是0.8
    })


后端配置:
(1)Nginx:主要是下方的gizp配置哦,直接复制粘贴就可以使用啦,亲测有效哦

server{
    //开启和关闭gzip模式
    gzip on;
    //gizp压缩起点,文件大于2k才进行压缩;设置允许压缩的页面最小字节数,页面字节数从header头得content-length中进行获取。 默认值是0,不管页面多大都压缩。建议设置成大于2k的字节数,小于2k可能会越压越大。
    gzip_min_length 2k;
    // 设置压缩所需要的缓冲区大小,以4k为单位,如果文件为7k则申请2*4k的缓冲区 
    gzip_buffers 4 16k;
    // 设置gzip压缩针对的HTTP协议版本
    gzip_http_version 1.0;
    // gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间
    gzip_comp_level 2;
    //进行压缩的文件类型
    gzip_types text/plain application/javascript text/css application/xml;
    // 是否在http header中添加Vary: Accept-Encoding,建议开启
    gzip_vary on;
}


(2)express的中间件:compression,主要用于进行gzip压缩,通常用于web性能优化,能对文本内容进行压缩,一般用于html文件;
安装:npm install compression --save
使用:

var compression = require('compression');
const app = express()
// 启用gzip
app.use(compression());

2、浏览器缓存
对静态资源进行缓存,根据是否需要重新向服务器发起请求来分类,将http请求分为强制缓存和对比缓存

3、CDN的使用
浏览器从服务器上下载css、js和图片等文件时都要和服务器连接,而大部分的服务器的带宽都有限,如果超过限制,网页就半天反应不过来,而CDN可以通过不同的域名来加载文件,从而使下载文件的并发连接数大大增加,且CDN具有更好的可用性,更低的网络延迟和丢包率

4、使用Chrome Performance查找性能瓶颈
Chrome的Performance面板可以录制一段时间内的js执行细节及时间,步骤:
a、打开Chrome开发者工具,点进Performance面板
b、点击Record开始录制
c、刷新页面或展开某个节点
d、点击stop停止录制,就可以查看了

四、网络层面的优化

1、重复请求的取消
第一次请求还没回来之前就进行了第二次同样的请求时,就应该把第二次请求取消掉,防止重复请求;
在axios请求中进行封装,采用拦截器进行处理,首先实现三个方法,当请求方式、请求URL和携带参数都一致时,就可以认为是同样的请求,因此在发起请求时,可以根据当前的请求方式、请求地址和携带的参数来生成一个唯一的key,同时为每个请求创建一个专属的cancelToken,然后将key和cancelToken函数以键值对的形式保存到map对象中,使用map对象的好处就是可以快速判断是否有重复的请求:

    // 用于根据当前的请求信息生成请求的key
    generateReqKey(config) {
      const { url, method, params, data } = config;
      return [url, method, qs.stringify(params), qs.stringify(data)].join("&");
    },
    // 用于将当前请求信息添加到pendingRequest对象中
    PendingRequest = new Map(),
    addPendingRequest(config) {
      const requestKey = this.generateReqKey(config)
      config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
        if(!this.PendingRequest.has(requestKey)) {
          this.PendingRequest.set(requestKey, cancel)
        }
      })
    },
    // 检查是否有重复的请求,若存在则需要取消已经发出的请求
    removeRequest(config) {
      const requestKey = this.generateReqKey(config)
      if (this.PendingRequest.has(requestKey)) {
        const CancelToken = this.PendingRequest.get(requestKey)
        CancelToken(requestKey)
        this.PendingRequest.delete(requestKey)
      }
    }

因为需要对所有的请求都进行处理,所以直接在拦截器来实现取消重复请求的操作,
(1)请求拦截器:作用是在请求发送前统一执行某些操作,比如在请求头中添加token字段
(2)响应拦截器:作用是在接收到服务器响应后统一执行某些操作,比如根据不同的状态码进行不同的响应操作

    axios.interceptors.request.use(config => {
      // 检查是否有重复的请求
      this.removeRequest(config)
      // 把当前请求添加到PendingRequest对象中
      this.addPendingRequest(config)
      const token = localStorage.getItem('token')
      if(token) {
        config.headers.Authorization = `Bearer ${token}`
      }
      return config
    }, error => {
      return Promise.reject(error)
    })
    axios.interceptors.response.use(res => {
      // 从PendingRequest对象中移除请求
      this.removeRequest(res.config)
      const {data} = config;
      return data
    }, error => {
      // 从PendingRequest对象中移除请求
      this.removeRequest(error.config)
      return Promise.reject(error)
    })

2、限制失败请求重试的次数,避免无效请求过多,导致大量的资源消耗

//在main.js设置全局的请求次数,请求的间隙
axios.defaults.retry = 4;  // 请求次数
axios.defaults.retryDelay = 1000;  // 请求间隙
//响应拦截
axios.interceptors.response.use(undefined, function axiosRetryInterceptor(err) {
    var config = err.config;
    // 如果配置不存在或未设置重试选项,则返回错误信息
    if(!config || !config.retry) return Promise.reject(err);
 
    // 设置变量即跟踪重试次数
    config.__retryCount = config.__retryCount || 0;
 
    // 检查我们是否已经超过了总重试次数
    if(config.__retryCount >= config.retry) {
        // 返回错误信息
        return Promise.reject(err);
    }
 
    // 重试次数加1
    config.__retryCount += 1;
 
    // 创建延时器等待发送重试请求
    var backoff = new Promise(function(resolve) {
        setTimeout(function() {
            resolve();
        }, config.retryDelay || 1);
    });
 
    // 返回调用AXIOS来重试请求
    return backoff.then(function() {
        return axios(config);
    });
});

3、善用缓存,减小网络请求的次数
4、断网处理:
在vuex中存放network的状态,根据network的状态判断是否需要加载断网组件,断网情况就加载断网组件,不加载对应的页面组件,点击刷新,就跳转到refresh页面然后立即返回来实现重新获取数据,所以新建refresh.vue,在beforeRouteEnter钩子中返回当前页面
 文章来源地址https://www.toymoban.com/news/detail-771043.html

// 断网页面
<template>  
    <div id="app">    
        <div v-if="!network">      
            <h3>我没网了</h3>      
            <div @click="onRefresh">刷新</div>      
        </div>    
        <router-view/>      
    </div>
</template>

<script>
    import { mapState } from 'vuex';
    export default {  
        name: 'App',  
        computed: {    
            ...mapState(['network'])  
        },  
        methods: {    
            // 通过跳转一个空页面再返回的方式来实现刷新当前页面数据的目的
            onRefresh () {      
                this.$router.replace('/refresh')    
            }  
        }
    }
</script>
在refresh.vue页面中:
// refresh.vue
beforeRouteEnter (to, from, next) {
    next(vm => {            
        vm.$router.replace(from.fullPath)        
    })    
}

到了这里,关于Vue项目性能优化方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 性能优化之--- 项目打包优化(vue)

    项目体积小也是优化性能的一个方向,这里以 Vue 工程为例; 当刚运行项目的时候,发现刚进入页面,就将所有的js文件和css文件加载了进来,这一进程十分的消耗时间。 如果打开哪个页面就对应的加载响应页面的js文件和css文件,那么页面加载速度会大大提升。 vue官方文档

    2024年02月09日
    浏览(48)
  • Vue 项目性能优化 — 实践指南

    Vue 框架通过数据双向绑定和虚拟 DOM 技术,帮我们处理了前端开发中最脏最累的 DOM 操作部分, 我们不再需要去考虑如何操作 DOM 以及如何最高效地操作 DOM;但 Vue 项目中仍然存在项目首屏优化、Webpack 编译配置优化等问题,所以我们仍然需要去关注 Vue 项目性能方面的优化,

    2024年02月11日
    浏览(50)
  • vue前端性能优化之分包策略、异步组件、Gzip压缩

    目录 一、Gzip压缩 二、异步组件 三、分包策略 最后           项目的性能优化是有完整项目经历的开发者都会遇到得一个问题。这是整个项目开发最后的一步,也是最关键的一步,做一个项目并不是单单完成功能就算结束了,作为开发者,更要站在用户角度去进行项目体

    2024年02月09日
    浏览(51)
  • 关于 Vue 项目性能优化技巧分享

    前言 Vue 框架通过数据双向绑定和虚拟 DOM 技术,帮我们处理了前端开发中最脏最累的 DOM 操作部分, 我们不再需要去考虑如何操作 DOM 以及如何最高效地操作 DOM;但 Vue 项目中仍然存在项目首屏优化、Webpack 编译配置优化等问题,所以我们仍然需要去关注 Vue 项目性能方面的优

    2024年02月04日
    浏览(36)
  • 前端项目部署自动检测更新后通知用户刷新页面(前端实现,技术框架vue、js、webpack)——方案二:轮询去判断服务端的index.html是否跟当前的index.html的脚本hash值一样

    当我们重新部署前端项目的时候,如果用户一直停留在页面上并未刷新使用,会存在功能使用差异性的问题,因此,当前端部署项目后,需要提醒用户有去重新加载页面。 vue、js、webpack 根据打完包之后生成的 script src 的hash值去判断 ,每次打包都会生成唯一的hash值,只要轮

    2024年01月23日
    浏览(44)
  • vue项目前端通用埋点方案

    埋点方案主要流程 1、 在 main.js 文件中生成 capol-log-uuid 埋点会话唯一id,并存入 sessionStorage 中 2、在 utils 文件夹下添加 commonLog.js 公共埋点方法类,提供3个方法: 添加埋点函数: CapolLog.pointAdd(dynamicInfo, el) 更新埋点函数: CapolLog.pointUpdate(id, type,updateData) 更新埋点辅助函数:

    2024年02月21日
    浏览(33)
  • 深入了解Vue-loader: 优化Vue.js项目开发的利器

      Vue-loader是一个用于加载Vue组件的webpack插件。它允许你编写单文件组件(SFC),并将它们转换为JavaScript模块,以便在浏览器中使用。这个工具非常有用,因为它可以帮助你在开发过程中更好地组织和管理你的Vue组件。 如何安装:  安装完毕后,你需要在webpack配置文件中添

    2024年01月17日
    浏览(48)
  • 前端性能优化——内存问题

    过高的内存资源占用会导致 Web 应用变慢,甚至崩溃。可以通过 window.performance.memory 查看浏览器的内存限制等信息。 Web 前端开发中存在许多内存问题,下面是一些常见的内存问题: 内存泄漏:当一个对象不再被使用,但仍然占用着内存空间,就会导致内存泄漏问题。在 Web

    2024年02月16日
    浏览(44)
  • 【前端】vue.js从入门到项目实战笔记

    【前端目录贴】 文本插值中的代码被解释为节点的文本内容,而HTML插值中的代码则被渲染为视图节点。 3.1.1 文本插值 文本插值的方式:用 双大括号 将要绑定的变量、值、表达式括住就可以实现,Vue将会 获取计算后的值 ,并以 文本的形式 将其展示出来。 结果: 3.1.2 HTM

    2024年01月21日
    浏览(53)
  • vite+vue3+ts搭建项目八(打包性能优化三:使用CDN)

    使用vite-plugin-cdn-import 下载npm包 官方github:https://github.com/MMF-FE/vite-plugin-cdn-import 开发环境使用本地的npm包,cdn是打包时候才生效 在vite.config.ts中通过importToCDN引入 注意事项 :网上很多教程,还需要在 build 的 rollupOptions 添加对应的 external ,如上注释所示,其实是不需要的,

    2024年02月02日
    浏览(103)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包