一、代码层面的优化
(1)v-if 和 v-show 区分使用场景
v-if是DOM的销毁和重建,v-show只是简单的控制css的display属性,v-if适用于不需要频繁切换条件的场景,v-show则适用于需要频繁切换条件的场景
(2)computed 和 watch 区分使用场景
computed是计算属性,当我们需要进行数值计算,并且依赖于其它数据时,应该使用computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算。
watch更多的是「观察」的作用,类似于某些数据的监听回调 ,当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
(3)使用keep-alive
根据业务决定那些页面使用keep-alive
(4)始终为 v-for 添加 key,并且不要将 index 作为key
id 作为 key 时,仅仅是移动了节点,并没有触发 Item 的重新渲染。index 作为 key 时,触发了 Item 的重新渲染,可想而知,当 Item 是一个复杂的组件时,必然会引起性能问题。
(5)事件销毁
Vue组件销毁时,会自动清理它与其他实例的连接,解绑它的全部指令及事件监听器,但是仅限于组件本身的事件。如果在js内使用addEventListener等方式是不会自动销毁的,我们需要在组件销毁时手动移除这些事件的监听比如removeEventListener,以免造成内存泄漏。
(6)css写在页面头部,js脚本写在页面底部或异步加载
css尽量写在head中,因为css加载会阻塞页面的加载,这是有好处的,这避免了页面加载时会出现css没加载完而导致的出现页面一闪的情况,同时,css的加载是会阻塞JS的执行,但不阻塞引入JS的加载。
js尽量写在HTML文本的底部,因为js的引入会阻塞页面的渲染,也依赖于DOM节点。所以,应该先让HTML,CSS先行加载,最后加载JS。
JS代码异步加载
- async:加载完成后立即执行,所以会在dom加载完之前执行,在async执行完之后,html再继续解析,如果是多个脚本,该方法不能保证脚本按顺序执行。
-
defer:加载完成等到HTML解析完之后才会执行,如果是多个脚本,按照加载的顺序依次执行。
其中蓝色线表示网络读取,红色线表示执行时间,这两个都是针对脚本的;绿色线表示HTML解析。
使用场景
如果有多个脚本,它们之间的依赖关系很强使用defer,依赖关系不强使用async或defer。
(7)CSS sprite(图像精灵)
它是将大大小小的图片合并为一张大图,再使用图片定位来显示对应的图片,这样可以减少http请求个数,提高页面加载速度。但也有个缺点就是既然是合成一张大图,那么很多小图片就依赖这一张图片,如果这个图片没有加载出来那么整个页面基本上就缺失了
(8)图片懒加载
对于图片过多的页面,为了加速页面加载速度,所以很多时候我们需要将页面内未出现的可视区域内的图片先不做加载,等到滚动到可视区域后再去加载。这样对于页面加载性能上会有很大的提升,也提高了用户体验。我们在项目中使用Vue的vue-lazyload插件:
(1)安装插件
npm install vue-lazyload --save-dev
(2)在入口文件main.js中引入并使用
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)
(3)在vue文件中将img标签的src属性直接改为v-lazy,从而将图片显示方式更改为懒加载显示
<img v-lazy="/static/img/1.png">
(9)路由懒加载
Vue 是单页面应用,可能会有很多的路由引入 ,这样使用 webpcak 打包后的文件很大,当进入首页时,加载的资源过多,页面会出现白屏的情况,不利于用户体验。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件,这样会大大提高首屏显示的速度,但是可能其他的页面的速度就会降下来。
路由懒加载:
const Foo = () => import('./Foo.vue')
const router = new VueRouter({
routes: [
{ path: '/foo', component: Foo }
]
})
(10)优化无限列表性能
如果你的应用存在非常长或者无限滚动的列表,那么需要采用 窗口化 的技术来优化性能,只需要渲染少部分区域的内容,减少重新渲染组件和创建 dom 节点的时间。 你可以参考以下开源项目 vue-virtual-scroll-list 和 vue-virtual-scroller 来优化这种无限列表的场景。
(11)第三方插件按需引入
我们在项目中经常需要引入第三方插件,如果我们直接引入 整个插件,会导致 项目体积太大,我们可以借助babel-plugin-component,然后只引入需要的组件,以达到减小项目体积的目的,以下是vue项目引入element-ui组件库为例:
- 首先安装babel-plugin-component
npm install babel-plugin-component -D
- 第二步是将.babelrc修改为:
{
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
- 第三步是在main.js中引入部分组件:
import Vue from 'vue';
import { Button, Select } from 'element-ui';
Vue.use(Button)
Vue.use(Select)
跟我们之前按需引入部分组件不同之处在于,我们是整体引入css样式import element-ui/lib/theme-chalk/index.css,现在这种方式不仅按需引入部分组件还按需引入部分样式
(12)减少ES6转为ES5的冗余代码
Babel 插件会在将 ES6 代码转换成 ES5 代码时会注入一些辅助函数,例如下面的 ES6 代码:
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 编译出来的代码的文件大小。
(1)首先,安装 @babel/plugin-transform-runtime
npm install @babel/plugin-transform-runtime --D
(2)然后,修改 .babelrc 配置文件为:
"plugins": ["@babel/plugin-transform-runtime"]
二、基础的 Web 技术优化
(1)开启 gzip 压缩
在打开网页时,会首先加载各种资源,js、css、图片等等,这些文件一般比较大,打开网页也比较慢,用户体验不好,所以提出gzip压缩,可以将文件缩小2-3倍,文件越小页面打开速度越快,需要配置nginx和webpack,在nginx中
// nginx开启gzip服务
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
// 需要开启gzip的格式
gzip_types text/plain text/css application/json application/x-javascript text/xml
application/xml application/xml+rss text/javascript image/jpeg image/gif image/png image/jpg;
配置完成后,需要重启一下nginx即可。
接下来我们就要在前端vue项目中进行gzip相关的配置了,首先我们需要安装一个插件:
npm i -D compression-webpack-plugin
安装完成后,在我们项目的 vue.config.js 中,引入该插件并配置一下:
const CompressionPlugin = require("compression-webpack-plugin");
module.export = {
configureWebpack: () => {
if (process.env.NODE_ENV === 'production') {
return {
plugins: [
new CompressionPlugin({
test: /\.js$|\.html$|\.css$|\.jpg$|\.jpeg$|\.png/, // 需要压缩的文件类型
threshold: 10240, // 归档需要进行压缩的文件大小最小值,我这个是10K以上的进行压缩
deleteOriginalAssets: false // 是否删除原文件
})
]
}
}
}
}
配置完成后,对项目进行 npm run build 打包之后,你可以在dist文件夹下看到相应的.gzip的文件,这就是进行压缩后生成的,这时我们在开发者工具中的network中查看我们的js或者其他文件的请求:
注意:webpack4+才会显示chunk开头的文件
Request Headers中会显示Accept-Encoding: gzip,Response Headers中会显示Content-Encoding: gzip这样就表示配置成功
(2)使用CDN
大型Web应用对速度的追求并没有止步于仅仅利用浏览器缓存,因为浏览器缓存始终只是为了提升二次访问的速度,对于首次访问的加速,我们需要从网络层面进行优化,最常见的手段就是CDN(Content Delivery Network,内容分发网络)加速。通过将静态资源(例如js、css、图片)缓存到离用户很近的相同网络运营商的CDN节点上,不但能提升用户的访问速度,还能节省服务器的带宽消耗,降低负载。
CDN是如何做到加速的呢?
其实这是CDN服务商在全国各个省份部署计算节点,CDN将网站的内容缓存在各个节点,不同地区的用户就会访问到离自己最近的相同网络线路上的CDN节点,当请求达到CDN节点后,节点会判断自己的内容缓存是否有效,如果有效,则立即响应缓存内容给用户,从而加快响应速度。如果无效,它会根据服务配置去我们的内容源服务器获取最新的资源响应给用户,并将内容缓存下来以便响应给后续访问的用户。因此,一个地区只要有一个用户先加载资源,在CDN中建立了 缓存 ,该地区的其他用户都会因此受益。
(3)预解析DNS
资源预加载是另一个性能优化技术,我们可以使用该技术来预先告知浏览器某些资源可能在将来会被使用到。通过DNS预解析来告诉浏览器未来我们可能从某个特定的URL获取资源,当浏览器真正使用到该域中的某个资源时就可以尽快地完成DNS解析。例如,我们将来可从example.com获取图片或音频资源,那么可以在文档顶部的标签中加入以下内容:
<link rel="dns-prefetch" href="//example.com">
当我们从该URL请求一个资源时,就不再需要等待DNS的解析过程。该技术对使用第三方资源特别有用。通过简单的一行代码就可以告知那些兼容的浏览器进行DNS预解析,这意味着当浏览器真正请求该域中的某个资源时,DNS的解析就已经完成了,从而节省了宝贵的时间。另外需要注意的是浏览器会对a标签的href自动启用预解析,所以a标签包含的域名不需要在head中手动设置link。但是在HTTPS下不起作用,需要meta来强制开启,这个限制的原因是防止窃听者根据DNS预解析推断显示在HTTPS页面中超链接的主机名。下面这句作用是强制打开a标签的域名解析:
<meta http-equiv="x-dns-prefetch-control" content="on">
(4)利用前端缓存
https://www.jianshu.com/p/cd3e7498aadc
Webpack层面优化
https://www.jianshu.com/p/f607114cf974
网友评论