大家平时浏览网页的时候有没有过这样的体验。某猫的响应速度为何这么快?体验为何这么流畅?为什么往下拉动时才加载图片?相反,某某银行网站的体验为何明显卡顿?Why?
带着这些问题,我们一起来思考并寻找答案。
目标
- 掌握前端性能优化的原理
- 了解主流前端性能优化实践
- 分析自身业务,选择合适的性能优化方式
浏览器的一个请求从发送到返回都经历了什么?
第一步、当用户在浏览器地址栏输入一个URL按下回车的时候,浏览器会将domain发送给域名服务器,DNS将domain对应的IP地址返回给浏览器。
第二步、浏览器会将IP地址及请求的参数携带到协议中,并发送到网络中去。
第三步、请求经过局域网、交换机、路由器、主干网络,发送到服务器。
第四步、服务器是一个MVC架构,请求进入服务器后,会在Controller进行逻辑处理和请求分发,然后发送给Model层,Model层会跟Redis和DB进行交互,最后将渲染好的页面通过View层返回给网络。
第五步、一个HTTP请求的Response就从服务端回到了浏览器,浏览器对返回回来的HTML,CSS,Js进行渲染。
下面用一个简单的图来描述这个过程。
网站在浏览器端是如何进行渲染的呢?
第一步、当浏览器接受到从服务器返回的HTML文档后,遍历文档节点,渲染成DOM树。同时,CSS资源请求回来后由浏览器生成响应的CSS树。
第二步、DOM树跟CSS树合并,生成Render树。
第三步、进一步的布局跟绘制。
实际上的绘制会更加复杂,HTML从上到下解析,与此同时会请求所需的外部资源,并对外部资源进行解析和执行,最后是页面的渲染。
请求过程中一些潜在的性能优化点
- dns是否可以通过缓存减少dns查询时间?
- 网络请求的过程走最近的网络环境?
- 相同的静态资源是否可以缓存?
- 能否减少请求HTTP请求的大小?
- 能否减少HTTP请求?
减少HTTP请求大小
减少HTTP请求大小的方法有很多种,主要方法有CSS压缩,Js压缩和混淆,图片优化。
CSS压缩
对于CSS文件,我们可以删除无效的代码,并且对CSS代码的语义进行合并。
Js压缩和混淆
对于Js代码,可以删除无效的代码,剔除注释,对代码的语义进行缩减和优化,Js混淆还可以带来保护代码的作用。
压缩:删除代码中所有注释、跳格符号、换行符号及无用的空格,从而压缩文件大小,优化页面加载速度。
混淆:经过编码将变量和函数原命名改为毫无意义的命名(如function(a,b,c,e,g)等),以防止他人窥视和窃取 Javascript 源代码,也有一定压缩效果。
压缩方法:
- 使用在线网站进行压缩(http://tool.oschina.net/jscompress)
- 使用html-minifier对html中的css/js进行压缩
- 使用clean-css对css进行压缩
- 使用uglifyjs2对js进行压缩
图片的优化
CSS雪碧图
把网站上用到的一些图片整合到一张单独的图片中,减少网站的HTTP请求数量。在线网站:http://www.sprite.com
《前端优化:css雪碧图实践应用详解》:https://blog.csdn.net/qq_31370987/article/details/53869742
在线压缩图片
在线地址:https://tinypng.com
减少HTTP请求数量
浏览器缓存
- 强缓存:在过期时间前浏览器可以直接从缓存中读取数据,而无需再次请求。与强缓存相关的header字段有:Cache-Control、Expires。
- 协商缓存:基于客户端和服务端协商的缓存机制,与协商缓存相关的header字段有:Last-Modified/if-Modified-Since、Etag/if-None-Match。
强缓存:Cache-Control
- max-age:指定的时间之内,是不会向服务端发起请求的。服务器端告诉浏览器,这张图片在这个时间内不会过期,都是有效的。
- s-maxage:指定缓存的时间,但只能指定public的缓存。
- private:缓存设备分为private缓存设备和public缓存设备。private缓存设备只能用于当前用户自己访问的缓存,比如用户的浏览器。
- public:缓存设备,比如CDN,可以供很多用户访问并读取信息。
- no-cache:不管怎么样,都会向服务器发起请求,不会从缓存读取。
- no-store:不缓存。
注意:
- s-maxage优先级高于max-age,它只能对public缓存设备生效。
- 当Cache-Control设置了s-maxage,浏览器不会从本地缓存去读取数据,而是向CDN发起请求。如果CDN的缓存是在s-maxage设置的时间之内,则CDN文件的缓存是不会过期的,此时会返回304状态码,并直接从CDN返回数据。如果CDN的缓存在s-maxage设置的时间之外,则浏览器需要向服务器发起请求,最终返回200状态码,并从服务器返回数据。
强缓存:Expires
缓存过期时间,用来指定资源的到期时间,是服务器端具体的时间。
告诉浏览器在过期时间前,浏览器可以直接从浏览器缓存取数据,而无需再次请求。
强缓存:有效期内,直接从缓存读取,不会向服务器发起请求。
协商缓存:能感知服务端文件是否发生变化。
协商缓存:Last-Modified/if-Modified-since
基于客户端和服务端协商的缓存机制。
last-modified : response header
if-modified-since : request header
服务器根据客户端传来的时间判断文件是否已过期,未过期返回304,浏览器可以到缓存中读取文件。如果已过期,则返回200,并返回文件。
last-modified的缺点:
- 某些服务端不能获取精确的修改时间。
- 文件修改时间变化,但文件内容没有变。
协商缓存:Etag/if-None-Match
文件内容的hash值。
Etag : response header
if-none-match : request header
分级缓存策略
200状态:当浏览器本地没有缓存或者下一层失效,或者用户点击Ctrl+F5时,浏览器直接去服务器下载最新数据。
304状态:【协商缓存】这一层由last-modified/etag控制。当下一层失效,或用户点击Ctrl+F5时,浏览器就会发送请求给服务器。如果服务器没有变化,则返回304给浏览器。
200状态:【强缓存】这一层由expires/cache-control控制。只要没有失效,浏览器直接访问缓存。
提升浏览器渲染效率
CSS性能会让JavaScript变慢
CSS head中阻塞页面的渲染。
CSS不阻塞脚本的加载,但会阻塞脚本的执行。(Js的执行依赖于CSS的属性)
解决方案:
1.CSS样式表置顶。
2.用link代替import。
3.提高CSS渲染效率。
重绘与回流
重绘(repaint):当只影响元素的外观,风格的属性发生变化时,就会触发重绘。
回流(reflow):当页面布局和几何属性改变时会发生回流。
回流会严重影响页面的性能,应该尽量避免回流的发生。
《回流(reflow)与重绘(repaint)》:https://www.cnblogs.com/dujingjie/p/5784890.html
触发页面重布局的属性
- 盒子模型相关属性会触发重布局
- 定位属性及浮动也会触发重布局
- 改变节点内部文字结构也会触发重布局
回流有关属性 | |||
---|---|---|---|
width | top | text-align | border |
height | bottom | overflow-y | min-height |
padding | left | font-weight | clear |
margin | right | overflow | vertival-align |
display | position | font-family | white-space |
border-width | float | line-height | font-size |
只触发重绘的属性
重绘有关属性 | |||
---|---|---|---|
color | background-image | outline-style | border-style |
background-position | outline-width | border-radius | background-repeat |
box-shadow | visibility | background-size | text-decoration |
outline-color | background | outline |
实战优化点
- 用translate替代top改变。
- 用opacity替代visibility。
- 不要一条一条修改DOM的样式,预先定义好class,然后修改DOM的className。
- 把DOM离线后修改,比如:先把DOM给 display : none,然后修改100次,再把它显示出来。
- 不要使用table布局,可能很小的一个小改动会造成整个table的重新布局。