性能优化实战

互联网项目,最重要的便是用户体验。对于网站的性能,在行业内有很多既定的指标,但就以前端er而言,我们应该更加关注以下指标:白屏时间、首屏时间、整页时间、DNS时间、CPU占用率。
今天,我们将从性能优化的以下方面展开介绍
一、网络传输性能优化
1、善用缓存,不重复加载相同的资源
浏览器的缓存策略
性能优化实战_第1张图片
(1)为了避免用户每次访问网站都得请求文件,我们可以通过添加 Expires 或 max-age 来控制这一行为。Expires 设置了一个时间,只要在这个时间之前,浏览器都不会请求文件,而是直接使用强缓存。而 max-age 是一个相对时间,建议使用 max-age 代替 Expires 。
(2)当浏览器对某个资源的请求没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的http状态为304并且会显示一个Not Modified的字符串。Last-Modified/If-Modified-Since:本地文件在服务器上的最后一次修改时间。缓存过期时把浏览器端缓存页面的最后修改时间发送到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行对比,如果时间一致,那么返回304,客户端就直接使用本地缓存文件。
Etag/If-None-Match:(EntityTags)是URL的tag,用来标示URL对象是否改变,一般为资源实体的哈希值。和Last-Modified类似,如果服务器验证资源的ETag没有改变(该资源没有更新),将返回一个304状态告诉客户端使用本地缓存文件。Etag的优先级高于Last-Modified,Etag主要为了解决Last-Modified 无法解决的一些问题:
文件也许会周期性的更改,但是他的内容并不改变,不希望客户端重新get;
If-Modified-Since能检查到的粒度是s级;
某些服务器不能精确的得到文件的最后修改时间。
配置缓存
①首先,我们先进入nginx的配置文档
$ vim nginxPath/conf/nginx.conf
②在配置文档内插入如下两项:
etag on; //开启etag验证
expires 7d; //设置缓存过期时间为7天
2.资源的打包压缩
不同于大部分放在服务端的后台代码,前端所有的文件程序代码都是要通过浏览器下载下来运行使用,这就牵扯到网络和请求延时,所以前端文件的精简和压缩决定了前端性能的第一步。
结合前端工程化思想,我们在对上线文件进行自动化打包编译时,通常都需要打包工具的协助,这里我推荐webpack,
在 webpack 可以使用如下插件进行压缩:
JavaScript:UglifyPlugin
CSS :MiniCssExtractPlugin
HTML:HtmlWebpackPlugin
(1)JS压缩:
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true // set to true if you want JS source maps
}),
…Plugins
]
}
(2)HTML压缩:
new HtmlWebpackPlugin({
template: __dirname + ‘/views/index.html’, // new 一个这个插件的实例,并传入相关的参数
filename: ‘…/index.html’,
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
chunksSortMode: ‘dependency’
})
(3)css压缩
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
module: {
rules: […, {
test: /.cssKaTeX parse error: Expected 'EOF', got '}' at position 487: … ] }̲] } (4)gzip…|.htmlKaTeX parse error: Can't use function '\.' in math mode at position 2: |\̲.̲css/,
// 超过4kb压缩
threshold: 4096
})
)
}
}
}
③在配置上面的压缩之后,执行npm run build命令,会发现生成的静态文件里面新增了后缀为gz的文件
性能优化实战_第2张图片
如果此时将项目部署到已开启了gzip的服务器如nginx里面之后,访问浏览器即可看到浏览器下载的是已压缩的文件
3、图片的资源优化
(1)对于固定图片,推荐https://tinify.cn/在线压缩之后再进行引入,支持png,jpeg类型的图片,属于有损压缩,去除图片一些不必要的元数据,把相似像素的24bit位用8bit位来表示,肉眼很难区分,压缩率70%。
(2)采用CSS雪碧图:把你的网站用到的一些图片整合到一张单独的图片中:
优点:减少HTTP请求的数量(通过backgroundPosition定位所需图片)。
缺点:整合图片比较大时,加载比较慢(如果这张图片没有加载成功,整个页面会失去图片信息)。
(3)对于非固定图片,常见的优化压缩主要有以下几种原则:
优先使用压缩率高的jpeg类型图片,缺点是不支持透明。
有条件的话使用webP(一种Google开发的新类型)类型图片是最佳选择,相比于jpeg,有更小的文件尺寸和更高的图像质量。
(4)使用base64格式的图片
(5)尽可能利用 CSS3 效果代替图片。有很多图片使用 CSS 效果(渐变、阴影等)就能画出来,这种情况选择 CSS3 效果更好。因为代码大小通常是图片大小的几分之一甚至几十分之一。
(6)图片的懒加载.。图片进入可视区域之后请求图片资源,没有到达可视区域前并不现实真正的src,而是类似一个1px的占位符。对于电商等图片很多,页面很长的业务场景适用。减少无效资源的加载。
(7)使用字体图标。不论是压缩后的图片,还是雪碧图,终归还是图片,只要是图片,就还是会占用大量网络传输资源。字体图标只是往HTML里插入字符和CSS样式而已,和图片请求比起来资源占用完全不在一个数量级,如果你的项目里有小图标,就是用矢量图吧。我最喜欢用的是阿里矢量图标库(网址:http://www.iconfont.cn/),里面有大量的矢量图资源
4、引入cdn。链接https://www.bootcdn.cn/
造成加载时间过慢的元凶是vendor文件,该文件存放的是项目中所有的第三方依赖。比如vuex、vue-router、jquery等。优化的一个要点就是分离第三方依赖。但是分离的时候要考虑到,即便将依赖分离后依赖文件仍然存在服务器上,而相对来说很多成熟类库会提供cdn结点,访问cdn会比访问自己的服务器要快,因此优化的第一步是对相关依赖用cdn方式引入。
(1)、index.html中
性能优化实战_第3张图片
(2)、使用了CDN,webpack就不需要再打包这几个依赖,但是webpack会默认追踪所有依赖,因此需要配置过滤的依赖项。打开webpack.base.conf.js, 增加如下配置:
性能优化实战_第4张图片

二、浏览器加载原理优化
浏览器渲染过程:
1、解析HTML生成DOM树。
2、解析CSS生成CSSOM规则树。
3、解析JS,操作 DOM 树和 CSSOM 规则树。
4、将DOM树与CSSOM规则树合并在一起生成渲染树。
5、遍历渲染树开始布局,计算每个节点的位置大小信息。
6、浏览器将所有图层的数据发送给GPU,GPU将图层合成并显示在屏幕上。

重排是由CPU处理的,而重绘是由GPU处理的,CPU的处理效率远不及GPU,并且重排一定会引发重绘,而重绘不一定会引发重排。所以在性能优化工作中,我们更应当着重减少重排的发生。
①重排(reflow):渲染层内的元素布局发生修改,都会导致页面重新排列,比如窗口的尺寸发生变化、删除或添加DOM元素,修改了影响元素盒子大小的CSS属性(诸如:width、height、padding)。
②重绘(repaint):绘制,即渲染上色,所有对元素的视觉表现属性的修改,都会引发重绘。
如何减少重排重绘?

1、用 JavaScript 修改样式时,最好不要直接写样式,而是替换 class 来改变样式。
2、如果要对 DOM 元素执行一系列操作,可以将 DOM 元素脱离文档流,修改完成后,再将它带回文档。推荐使用隐藏元素(display:none)或文档碎片(DocumentFragement),都能很好的实现这个方案。
3、将没用的元素设为不可见:visibility: hidden,这样可以减小重绘的压力,必要的时候再将元素显示。
4、图片在渲染前指定大小:因为img元素是内联元素,所以在加载图片后会改变宽高,严重的情况会导致整个页面重排,所以最好在渲染前就指定其大小,或者让其脱离文档流。
5、script引入的外部js会阻塞后面节点的渲染,所以外部js尽量放在body底部。
6、在head里面尽量不要引入js。
7、如果要引入js 尽量将js内嵌。
8、把内嵌js放在所有link引入css的前面。
9、对于要阻塞后续内容的的外部js在script标签里,需要增加defer来解决。
10、 使用 transform 和 opacity 属性更改来实现动画。在 CSS 中,transforms 和 opacity 这两个属性更改不会触发重排与重绘,它们是可以由合成器(composite)单独处理的属性。
11、使用 transform 替代 top
12、使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局)
13、不要把节点的属性值放在一个循环里当成循环里的变量。
14、不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局
15、动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用 requestAnimationFrame
16、CSS 选择符从右往左匹配查找,避免节点层级过多
17、避免设置多项内联样式(Avoid setting multiple inline styles)
18、应用元素的动画,使用 position 属性的 fixed 值或 absolute 值
19、避免使用CSS的JavaScript表达式 (仅 IE 浏览器)
三、JS代码
1、使用 requestAnimationFrame 来实现视觉变化。
大多数设备屏幕刷新率为 60 次/秒,也就是说每一帧的平均时间为 16.66 毫秒。在使用 JavaScript 实现动画效果的时候,最好的情况就是每次代码都是在帧的开头开始执行。而保证 JavaScript 在帧开始时运行的唯一方式是使用 requestAnimationFrame。
如果采取 setTimeout 或 setInterval 来实现动画的话,回调函数将在帧中的某个时点运行,可能刚好在末尾,而这可能经常会使我们丢失帧,导致卡顿。
2、当判断条件数量越来越多时,越倾向于使用 switch 而不是 if-else。switch只判断一次
3、注意代码的的时间复杂度(大O表示法)
4、 不要覆盖原生方法
无论你的 JavaScript 代码如何优化,都比不上原生方法。因为原生方法是用低级语言写的(C/C++),并且被编译成机器码,成为浏览器的一部分。当原生方法可用时,尽量使用它们,特别是数学运算和 DOM 操作。
5、js的防抖和节流

你可能感兴趣的:(vue)