导航
关于前端性能优化相关的技术知识,网上随便搜一些就有很多,本文将系统性的从初级到高级的思路,总结移动前端性能优化各个方面的相关技术点,内容来自笔者以往经验的总结,希望读者可以花些时间看看。
在目前大多数刚从事前端开发,或者是正在学习前端开发的同学来说,性能优化对于他们可能还比较远,但是脱颖而出,拉开差距的点,往往就在与性能优化,和理论知识不同,性能优化往往来自日常的工作经验中总结而来,也是目前大厂面试前端必问的知识点,所以重要性就不言而喻了。
首先,重要的事情说三遍:
移动web性能优化原理知识同样适用于PCweb端! 移动web性能优化原理知识同样适用于PCweb端! 移动web性能优化原理知识同样适用于PCweb端!
为什么要压缩?
不同于大部分放在服务端的后台代码,前端所有的文件程序代码都是要通过浏览器下载下来运行使用,这就牵扯到网络和请求延时,所以前端文件的精简和压缩决定了前端性能的第一步。
介于目前的前端框架类库,webpack,vue-cli等等,已经可以直接将这一步操作集成到我们的系统项目中了,可以直接查看各个框架的文档来进行配置,单纯的使用原生技术,可以参考下面:
HTML代码压缩就是压缩这些在文本文件中有意义,但是在HTML中不显示的字符,包括空格,制表符,换行符等,还有一些其他意义的字符,如HTML注释也可以被压缩。
JavaScript压缩,主要是去除多余的换行和空格等等,对于语法来说,JavaScript可以选择混淆压缩和非混淆压缩,无论哪种压缩都是为了减少JavaScript的文件大小,当然出于前端代码保护来看,混淆压缩会大大破坏原有的阅读逻辑,增加压缩比,从而给代码添加一层保护。
CSS压缩,同理是去除多余的换行和空格等等,由于CSS文件的特殊性暂时无法实现混淆压缩,压缩主要是将大量的换行去除,可以减少不少的文件大小。
对于常见的前端项目,关于图片的使用,主要有以下两种:
CDN
上,前端通过链接请求。对于固定图片,推荐https://tinypng.com/在线压缩之后再进行引入,支持png,jpeg类型的图片,属于有损压缩,去除图片一些不必要的元数据,把相似像素的24bit位用8bit位来表示,肉眼很难区分,压缩率70%。图片描述
backgroundPosition
定位所需图片)。缺点:整合图片比较大时,加载比较慢(如果这张图片没有加载成功,整个页面会失去图片信息)。对于非固定图片,常见的优化压缩主要有以下几种原则:优先使用压缩率高的jpeg
类型图片,缺点是不支持透明。有条件的话使用webP(一种Google开发的新类型)类型图片是最佳选择,相比于jpeg,有更小的文件尺寸和更高的图像质量。
在前端编码的时候将css、js等静态资源文件合并压缩之外,我们还可以在页面中将多个css、js的请求合并为一个请求。(通常通过使用构建工具(如 webpack
)来打包多个 CSS 和 JS 文件,从而减少 HTTP 请求的次数)文件的合并带来的是http请求数的减少,尤其是在移动端,每一个http请求带来的是慢启动
,三次握手
,连接建立
,所以资源的合并是由为重要的,合并和不合并对比:
图片描述
HTML页面加载渲染的过程:
根据上图我们来屡一下整个流程:
阻塞
其他的下载和呈现。那么如何解决和避免阻塞的问题呢,我们通过测试代码分别测试不同情况下引入js和css的问题如下:<!DOCTYPE html>
<html>
<head>
<title>test</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" media="screen">
<link rel="stylesheet" type="text/css" href="page-animation.css" media="screen">
<script type ="text/javascript">
var f = 1;
f++;
</script>
</head>
<body>
<img src=”download-button.png”>
</body>
</html>
测试过程省略,可以参考这里,我们可以得到如下的结论:
<script src>
引入的外部js会阻塞后面节点的渲染,所以外部js尽量放在body底部。<script src>
,需要**增加defer
**来解决。如果一个H5页面没有利用任何缓存,那么这个页面将没有任何存在的意义。
从HTTP协议缓存,到浏览器缓存,再到APP Cache,一直在最近比较火的Service worker,我们可以选择多种的缓存方式,入门基本来说说HTTP协议缓存:
当浏览器对某个资源的请求命中了强缓存时,返回的HTTP状态为200,在chrome的开发者工具的network里面 size会显示为from disk cache,这种情况下是不用发送任何请求,如下图图片描述
Expires:指定了在浏览器上缓冲存储的页距过期还有多少时间,等同Cache-control中的max-age的效果,如果同时存在,则被 Cache-Control 的 max-age 覆盖。
Cache-Control:
public:响应被缓存,并且在多用户间共享。
private:默认值,响应只能够作为私有的缓存(e.g., 在一个浏览器中),不能再用户间共享;
no-cache:响应不会被缓存,而是实时向服务器端请求资源。
max-age:数值,单位是秒,从请求时间开始到过期时间之间的秒数。基于请求时间(Date字段)的相对时间间隔,而不是绝对过期时间;协商缓存:Last-Modified & Etag
当浏览器对某个资源的请求没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的http状态为304并且会显示一个Not Modified的字符串,比如你打开京东的首页,按f12打开开发者工具,再按f5刷新页面,查看network,可以看到有不少请求就是命中了协商缓存的:
Last-Modified/If-Modified-Since:本地文件在服务器上的最后一次修改时间。缓存过期时把浏览器端缓存页面的最后修改时间发送到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行对比,如果时间一致,那么返回304,客户端就直接使用本地缓存文件。
Etag/If-None-Match:(EntityTags)是URL的tag,用来标示URL对象是否改变,一般为资源实体的哈希值。和Last-Modified类似,如果服务器验证资源的ETag没有改变(该资源没有更新),将返回一个304状态告诉客户端使用本地缓存文件。Etag的优先级高于Last-Modified,Etag 主要为了解决 Last-Modified 无法解决的一些问题。
懒加载对于移动web端,尤其是最常见的滚动加载场景是一项非常重要的优化措施。而预加载则常常应用于多tab场景的页面,让用户更快的看到打开的下一个页面。
懒加载
图片进入可视区域之后请求图片资源。
对于电商等图片很多,页面很长的业务场景适用。
减少无效资源的加载。
并发加载的资源过多会阻塞js的加载,影响网站的正常使用。
img src被设置之后,webkit解析到之后才去请求这个资源。所以我们希望图片到达可视区域之后,img src
才会被设置进来,没有到达可视区域前并不现实真正的src,而是类似一个1px的占位符。
预加载
ok,读到这里,对于一些刚入门的前端玩家,或者是还在学习前端的同学,掌握了上面的入门级性能优化基础知识,才能算是基本的合格,真正更进一步的优化,更适合移动端web的性能点,可以参考进阶版:
gzip是GNUzip的缩写,最早用于UNIX系统的文件压缩。HTTP协议上的gzip编码是一种用来改进web应用程序性能的技术,web服务器和客户端(浏览器)必须共同支持gzip。目前主流的浏览器,Chrome,firefox,IE等都支持该协议。常见的服务器如Apache,Nginx,IIS同样支持gzip。
gzip流程:
Nginx中开启gzip:
前端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或者其他文件的请求:
HTTP/2是HTTP协议自1999年HTTP 1.1发布后的首个更新,主要基于SPDY协议(是Google开发的基于TCP的应用层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验)。
优化原理:
根据上文中说的资源合并问题,浏览器可以同时建立有限个TCP连接,而每个连接都要经过慢启动
,三次握手
,连接建立
,HTTP1.1为了解决这个问题推出了keep-alive,即保持连接不被释放,但是真正的这些连接下载资源是一个线性的流程:一个资源的请求响应返回后,下一个请求才能发送。这被称为线头阻塞,为了彻底解决此问题,HTTP2.0带来了多路复用:
HTTP2.0的其他新特性也有助于页面的打开速度:
现在回过头来探讨一下上文说的资源合并问题,有了HTTP2.0之后,我们是否还需要合并资源,目前看需要遵循下面的原则: