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.lognew UglifyJsPlugin({uglifyOptions: {compress: {warnings: false,drop_console: true, //注释consoledrop_debugger: true, //注释debuggerpure_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', // 压缩算法,官方默认压缩算法是gziptest: /\.js$|\.css$|\.html$|\.eot$|\.woff$/, // 使用gzip压缩的文件类型threshold: 10240, // 以字节为单位压缩超过此大小的文件,默认是10240minRatio: 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对象的好处就是可以快速判断是否有重复的请求:
// 用于根据当前的请求信息生成请求的keygenerateReqKey(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);}// 重试次数加1config.__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钩子中返回当前页面
// 断网页面
<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项目性能优化方案相关推荐
- Vue 项目性能优化方案
前言 Vue 框架通过数据双向绑定和虚拟 DOM 技术,帮我们处理了前端开发中最脏最累的 DOM 操作部分, 我们不再需要去考虑如何操作 DOM 以及如何最高效地操作 DOM:但 Vue 项目中仍然存 ...
- vue项目性能优化——断点续传
vue项目性能优化 用户上传文件的时候,如果文件过大,那么上传可能就会很耗时.而且一旦上传的过程中发生了网络中断,那上传就前功尽弃了.为了提高用户的体验,我们可以选择断点续传,也就是把文件切分成小块后 ...
- Vue项目性能优化篇
Vue项目性能优化是个老生常谈的问题了,本人开发过程中也查过很多关于Vue项目优化的文章,每篇文章说的都差不多,本章我就结合我的心得和大家的智慧做一个总结. 1.懒加载 懒加载应该是提高性能的最简单有 ...
- 前端Vue 项目性能优化
前言 Vue 框架通过数据双向绑定和虚拟 DOM 技术,帮我们处理了前端开发中最脏最累的 DOM 操作部分, 我们不再需要去考虑如何操作 DOM 以及如何最高效地操作 DOM:但 Vue 项目中仍然存 ...
- 接手同事vue项目两个月的血和泪,关于vue项目性能优化,缩短首屏加载时间
最近接手了别人做的vue项目,项目跑起来后,有些页面很卡,首屏加载也慢,打包速度也慢.于是,研究了很久vue的项目性能优化,下面我将从两个部分来详解vue项目的性能优化: 代码优化 webpack打包 ...
- 收藏这些vue项目性能优化方式,总有一天能用上
vue项目如何进行性能优化?下面本篇文章给大家分享一些vue项目一定会用到的性能优化方法,希望对大家有所帮助! 提起性能优化 很多人眼前浮现的面试经验是不是历历在目呢?反正,性能优化在我看来他永远是前 ...
- vue项目性能优化(图片优化)
一.图片保存阶段 ps 或 sketch 等图片,保存时或保存后,使用photoshop .jpg 图片选择 "连续" .png图片选择 "优化" 二. 图片压 ...
- 前端Vue项目打包性能优化方案
文章目录 一.前言 二.优化方案 1丶路由懒加载(代码分割) 2丶第三方插件按需加载 3丶常用插件库使用CDN加速 4.gzip压缩 5.打包不生成map文件 三.工具推荐 可视化分析包大小 总结 一 ...
- vuejs项目性能优化 - 总结篇
首页等页面加载慢?打包编译后css/js文件过大?试试压缩.路由懒加载等技术 打包编译后,过大的文件如:app.css.app.js.vendor.js 本着 "开发环境".&qu ...
最新文章
- MPB:生态环境中心陈保冬组-基于高通量测序技术的丛枝菌根真菌多样性研究方法...
- Coursera algorithm II PA4
- sliverlight--无法启动调试。
- 【Zabbix】CentOS6.9系统下部署Zabbix-server 3.0
- [转载]今天安装sql2000,老是出挂起的错误。所以找了找看见了这个方法。
- 讲讲 Python Launcher 是什么鬼东西?
- android 导入so库
- LNMP服务跨省迁移的解决方案
- filepath直接指定到文件名吗_PyTest运行指定的测试集
- 面向对象:包装类、对象处理、类成员
- 浅谈python MRO与Mixin模式
- rabbitmq接口异常函数方法_[项目更新] 集成RabbitMQ队列与EventBus总线
- vue中对话框关闭以后清空对话框中input,select内容
- java多继承_为什么 Java 不支持类多重继承?
- 集合set中的基数cardinality是什么意思
- 对算法的认识——逻辑回归
- 机器学习刻画股票市场结构和可视化——以上证50成分股为例
- 统信UOS系统安装详细教程(小白也能装系统啦~)
- APP性能测试——启动时间
- antv图例出现分页_自定义图例组件