整理了18条React的组件性能优化方案,开发React的可以去看看:
18条React的组件性能优化整理 |求关注😘,求点赞😘,鼓励一下😘
整理了18条Vue开发常用的项目代码和性能优化方案,后期会不断更新添加。
1、v-if和v-show
区别:v-if为false时不渲染DOM,v-show渲染DOM
- 权限相关的展示用v-if
- 其他频繁切换用v-show,不频繁切换用v-if
- 使用v-if可以减少DOM数量,加快页面渲染
- 使用三木运算符、&&或者||替代v-if
- v-if里面的表达式与判断,建议在
methods
和computed
里面封装成一个方法,方便复用 - 错误优先出return
if (!valid) {
this.$message.error('信息输入有误');
return;
}
2、v-for和v-if
- 不要在v-for中使用v-if,因为v-for的优先级高,每一次都需要遍历整个数组,影响渲染速度,如需要渲染部分,替换成computed属性或者提前js处理好
- v-for遍历必须为item添加key,key方便vue.js内部机制精准找到该条列表数据
- key避免使用index作为标识符,原因:逆序添加、逆序删除等破坏顺序的操作,会产生没有必要的真实DOM更新
3、使用解构赋值以及函数默认值
function add([x, y]){ return x + y; }
add([1, 2]); // 3
[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]
function move({x = 0, y = 0} = {}) { return [x, y]; }
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]
[1, undefined, 3].map((x = 'yes') => x);
// [ 1, 'yes', 3 ]
4、多使用计算属性
- 计算属性可以依赖多个数据,任何一个数据变动,计算都会重新执行
- 计算属性可以依赖其他计算属性
- 计算属性不仅可以依赖当前vue实例,还可以依赖其他实例的数据
- 计算属性不能调用,不能传参数; 方法需要调用,可以传参
- 计算属性默认会缓存计算结果; 方法没有缓存
- 基于原有的data,prop,computed等数据派生出别的数据
computed: {
reversedText: function () {
//这里的this指向的是当前的vue实例
//如果这两的text是后台接受的数据,最好加个判断数据为不为空
return this.text.split(',').reverse().join(',');
}
}
5、合理利用Vue生命周期
- 减少在created生命周期中做ajax请求,而是放在mounted生命周期中,以便不阻塞页面生成dom
6、提取公共样式、公共js和公共表单验证
- 复用的样式应当提取到公共的样式文件中复用
- 公共的方法应当提取到公共的js中复用
- 可复用表单验证的提取到公共文件中
7、长列表性能优化-冻结数据
Vue
会通过object.defineProperty
对数据进行劫持,来实现视图响应数据的变化
Object.defineProperty(obj,’b’,{get(){return 123}})
有时组件就是纯粹的数据展示,不会有变化,为了减少组件初始化,我们可以通过object.freeze
方法来冻结一个对象,vue就不会对数据进行劫持了
Object.freeze(users) //冻结就不能进行get和set转换
8、优化无限列表性能
- 随着数据越来越多,DOM节点越来越多,导致性能开销大,Vue的加载和刷新的性能下降,
- 可以用 vue-virtual-scroller 和 vue-virtual-scroller-list 优化
9、释放组件资源
- Vue组件销毁时,会自动清理它与其他实例的链接,解绑它的全部指令及事件监听器,但是仅限于组件本身的事件。
- 如果在js内使用了addEventListener,定时器等方式时不会自动销毁的,组件销毁时要手动移除,避免内存泄露。
created(){
addEventListener(‘click’,this.click,false)
}
beforeDestroy(){
removeEventListener(‘click’,this.click,false)
}
10、图片资源优化
- 小图标可使用SVG或者字体图标
- 小图标可制作雪碧图,多张图合并到一张,只需一次请求,可以减小建立连接的消耗
- 通过base64和webp的方式加载小型图片
- 能通过cdn加速的大图尽量用cdn
- 使用懒加载
- 压缩图片大小 ,纯静态的图片,可以统一压缩,无损压缩 tinpng压缩 Webpack不建议加图片压缩,严重影响打包速度 动态图片建议后端压缩,付费云服务
11、图片资源懒加载
安装
$ npm install vue-lazyload —save-dev
在main.js引入
import VueLazyLoad from ‘vue-lazyload’
Vue.use(VueLazyload, {
preLoad: 1.3,
error: 'dist/error.png',
loading: 'dist/loading.gif',
attempt: 1
})
页面使用
//图片懒加载
<img v-lazy="img" v-for="img in list" :key="img">
//背景图懒加载
<div v-lazy:background-image="img" ></div>
详细介绍请查看官方链接 ue-virtual-scroller
12、 路由懒加载
- webpack内部构建时,会把这种包单独解析成一个js文件
- 注意:懒加载的路由太多的话会导致打包性能下降
- 两种方式:
{
path: '/home',
component: () => import(/* webpackChunkName: "Home" */ 'pages/home/index.vue');
//component: resolve => (require['pages/home/index.vue'],resolve);
meta: {
name: '首页',
}
}
路由懒加载就是异步组件,异步组件不宜太多,太多有打包性能问题。
普通组件也可以用异步组件:
components:{
Home:()=>import('@/component/about.vue')
}
13、按需引入、按需加载
- 第三方插件按需引入
- element-UI 按需引入
- ant-design-vue 按需引入
- lodash 按需引入
import debounce from ‘lodash/debounce’
14、上线打包不生成.map文件
.map文件的作用是帮助编译后的代码调试,占用空间较大,所以上线时可以不生成.map文件,否则造成源码泄漏,在vue.config.js文件
productionSourceMap: false, //是否在构建生产包时生成 sourceMap 文件,
15、生产环境打包压缩Gzip
- vue-cli3.0和vue-cli4.0是没有productionGzip配置的,需要使用
compression-webpack-plugin
来实现生产环境打包压缩Gzip - 使用compression-webpack-plugin步骤:
$ npm i -D compression-webpack-plugin
在vue.config.js 文件中配置
const compressionWebpackPlugin = require('compression-webpack-plugin'); //引入插件
const productionGZipExtensions = ['js', 'css']; //压缩的文件类型
module.exports = {
//简单方式
configureWebpack: {
plugins: [
new compressionWebpackPlugin({
//[file] 会被替换成原始资源。[path] 会被替换成原始资源的路径, [query] 会被替换成查询字符串。默认值是 "[path].gz[query]"
asset: '[path].gz[query]', // 提示compression-webpack-plugin@3.0.0的话asset改为filename
algorithm: 'gzip',
//所有匹配该正则的资源都会被处理。默认值是全部资源
test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
//大小大于该值的资源会被处理。单位是 bytes。默认值是 0
threshold: 10240,
//压缩率小于这个值的资源才会被处理,默认值是 0.8
minRatio: 0.8
})
]
},
// 高级的方式
// configureWebpack: config => {
// if (process.env.NODE_ENV === 'production') {
// 生产环境
// config.plugins.push(
// new CompressionWebpackPlugin({
// })
// );
// } else {
// 开发环境
//}
// },
}
服务器端开启Gzip,NGINX配置
server{
gzip on;
gzip_buffers 32 4K;
gzip_comp_level 6;
gzip_min_length 100;
gzip_types application/javascript text/css text/xml;
gzip_disable "MSIE [1-6]\."; #配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持)
gzip_vary on;
}
- 运行
npm run build
打包上线项目,检测:打开Chrome控制台,可以看到Network下的Response Headers中返回了Content-Encoding: gzip
,表明gzip开启成功。而Request Headers里面的Accept-Encoding: gzip
只是表示前端(用户浏览器)支持gzip的压缩方式
16、首屏渲染优化
- 路由懒加载
- 在首页加入loading动画,骨架屏
- 预渲染,数据不太变动的,直接预渲染为静态页面
- 服务器渲染,如果仅仅首屏渲染慢,不建议用,如果要解决SEO,用
17、预渲染
服务端渲染与预渲染区别
- 客户端渲染:用户访问 url,请求 html 文件,前端根据路由动态渲染页面内容。关键链路较长,有一定的白屏时间;
- 服务端渲染:用户访问 url,服务端根据访问路径请求所需数据,拼接成 html 字符串,返回给前端。前端接收到 html 时已有部分内容;
- 预渲染:构建阶段生成匹配预渲染路径的 html 文件(注意:每个需要预渲染的路由都有一个对应的 html)。构建出来的 html 文件已有部分内容
服务端渲染与预渲染共同点,针对单页应用,服务端渲染和预渲染共同解决的问题:
- SEO:单页应用的网站内容是根据当前路径动态渲染的,html 文件中往往没有内容,网络爬虫不会等到页面脚本执行完再抓取;
- 弱网环境:当用户在一个弱环境中访问你的站点时,你会想要尽可能快的将内容呈现给他们。甚至是在 js 脚本被加载和解析前;
- 低版本浏览器:用户的浏览器可能不支持你使用的 js 特性,预渲染或服务端渲染能够让用户至少能够看到首屏的内容,而不是一个空白的网页。
预渲染实现
//puppeteer 二进制包镜像
$ npm config set puppeteer_download_host=https://npm.taobao.org/mirrors
$ npm i puppeteer
$ npm i prerender-spa-plugin --save -dev
确保路由模式是history
const router = new Router({
mode: 'history', // 预渲染一定要模式改成history
routes: routes
})
在vue.config.js配置
这里 publicPath得注释掉,否则打包后图片和资源链接会失效
const PrerenderSPAPlugin = require('prerender-spa-plugin');
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;
configureWebpack: {
plugins: [
new PrerenderSPAPlugin({
// 生成文件的路径,也可以与webpakc打包的一致。
// 下面这句话非常重要!!!
// 这个目录只能有一级,如果目录层次大于一级,在生成的时候不会有任何错误提示,在预渲染的时候只会卡着不动。
staticDir: path.join(__dirname,'dist'),
// 对应自己的路由文件,比如a有参数,就需要写成 /a/param1。
routes: ['/', '/about'],
// 这个很重要,如果没有配置这段,也不会进行预编译
renderer: new Renderer({
inject: { foo: 'bar' },
headless: false,
// 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。
renderAfterDocumentEvent: 'render-event',
renderAfterTime: 10000,//超时时间
timeout: 0,
maxConcurrentRoutes: 20,//打包页面的最大数
navigationParams: {
timeout: 0
}
})
}),
]
}
使用vue-meta-info插件,改变link、title、meta等
$ npm i vue-meta-info
//main.js
import MetaInfo from 'vue-meta-info'
Vue.use(MetaInfo);
new Vue({
router,
render: h => h(App),
//这句非常重要,否则预渲染
mounted () {
document.dispatchEvent(new Event('render-event'))将不会启动
}
}).$mount("#app");
//路由页面
export default {
metaInfo: {
//改变当前路由的title
title: 'title',
//改变当前路由的link
link: [
{
rel: 'baidu',
href: 'https://www.22.com/'
},
],
},
data(){
return{}
}
}
正确配置完,刷新后404,部署到服务器就可以了 涉及到发送请求,配置一个serve代理 prerender-spa-plugin、 vue-meta-info
18、大型项目配置多入口多出口模式
- 单页面的工程,main.js是整个项目唯一的入口,整个项目都在一个index.html外壳中。
- 在大型项目中,单页面易负载过重,频繁切换业务模块可能会造成浏览器内存持续上涨、页面卡顿崩溃等。
- 基于以上原因,可以采用多入口的模式,满足页面需要分开部署的场景,解决了页面卡顿和内存上涨问题。