前端性能优化

作者 Zhendong Ho 日期 2018-10-22
前端性能优化

大家平时浏览网页的时候有没有过这样的体验。某猫的响应速度为何这么快?体验为何这么流畅?为什么往下拉动时才加载图片?相反,某某银行网站的体验为何明显卡顿?Why?

带着这些问题,我们一起来思考并寻找答案。

目标

  • 掌握前端性能优化的原理
  • 了解主流前端性能优化实践
  • 分析自身业务,选择合适的性能优化方式

浏览器的一个请求从发送到返回都经历了什么?

第一步、当用户在浏览器地址栏输入一个URL按下回车的时候,浏览器会将domain发送给域名服务器,DNS将domain对应的IP地址返回给浏览器。

第二步、浏览器会将IP地址及请求的参数携带到协议中,并发送到网络中去。

第三步、请求经过局域网、交换机、路由器、主干网络,发送到服务器。

第四步、服务器是一个MVC架构,请求进入服务器后,会在Controller进行逻辑处理和请求分发,然后发送给Model层,Model层会跟Redis和DB进行交互,最后将渲染好的页面通过View层返回给网络。

第五步、一个HTTP请求的Response就从服务端回到了浏览器,浏览器对返回回来的HTML,CSS,Js进行渲染。

下面用一个简单的图来描述这个过程。

img

网站在浏览器端是如何进行渲染的呢?

第一步、当浏览器接受到从服务器返回的HTML文档后,遍历文档节点,渲染成DOM树。同时,CSS资源请求回来后由浏览器生成响应的CSS树。

第二步、DOM树跟CSS树合并,生成Render树。

第三步、进一步的布局跟绘制。

实际上的绘制会更加复杂,HTML从上到下解析,与此同时会请求所需的外部资源,并对外部资源进行解析和执行,最后是页面的渲染。

img

请求过程中一些潜在的性能优化点

  • 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

img

《前端优化: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:不缓存。

注意:

  1. s-maxage优先级高于max-age,它只能对public缓存设备生效。
  2. 当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的缺点:

  1. 某些服务端不能获取精确的修改时间。
  2. 文件修改时间变化,但文件内容没有变。

协商缓存: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

实战优化点

  1. 用translate替代top改变。
  2. 用opacity替代visibility。
  3. 不要一条一条修改DOM的样式,预先定义好class,然后修改DOM的className。
  4. 把DOM离线后修改,比如:先把DOM给 display : none,然后修改100次,再把它显示出来。
  5. 不要使用table布局,可能很小的一个小改动会造成整个table的重新布局。