6-1.前端性能优化(一)
引言
Web性能黄金准则:因为网站只有10%~20%的响应时间花在了下载HTML文档上,其余的80%~90%时间花在了下载页
面的所有组件上。
感谢雅虎的工程师总结的14条前端优化法则,使得我们可以站在巨人的肩膀上。《高性能网站建设》这本书的规则顺
序是按照其重要性来排名的:
规则一:减少HTTP请求。减少HTTP请求作为第一个规则,足见其重要性。根据黄金法则,减少组件数量从而减少
HTTP请求是最有效的性能优化方式,其中有几项技术值得提一下:CSS Sprites。应该前端人都比较熟悉了,
把图片整合到一个大图里,利用background-position来定位。data:URL。值得一说把图片变为内联的,减少
了图片请求,webpack里图片小于8kb就会转为base64的data:URL。合并脚本和CSS。
规则二:使用CDN。这个规则不用多说,分发内容使之更靠近终端用户,减少了请求时间。
规则三:添加Expires头。善用缓存,给长久不变的内容组件设置有效期较久的Expires头。
规则四:压缩组件。利用gzip等内容编码对文档或组件进行压缩,通常能将相应数据量减少70%左右。
规则五:将样式表放在顶部。页面在打开工程中逐步呈现,用户会觉得页面快一些,也让用户在等待过程中有一个良好
的反馈。把CSS放在底部的话有可能出现白屏现象。
规则六:将脚本放在底部。页面下载脚本时会阻止其他内容下载与呈现,以防止浏览器的重绘重排。所以把脚本放在
页面的底部不会阻止页面内容的呈现,而且页面一些可视化组件可以尽早下载而不被阻塞。
规则七:避免使用CSS表达式。CSS表达式会进行频繁的求值,导致了性能低下。
规则八:使用外部JavaScript和CSS。纯粹而言,内联更快一些,因为满足了规则一的减少HTTP请求,但是这个问
题上,一定要考虑缓存带来的性能优化,外部文件很有可能被缓存下来,从而提升了性能。
规则九:减少DNS查找。善用DNS缓存,比如持久连接。
规则十:精简JavaScript。移除不必要的字符空格,我们常见的.min.js就是如此。
规则十一:避免重定向。3xx的响应状态码代表着一股重定向的响应。其中URL结尾缺少斜线造成的重定向需要特别注
意,不要因为这一点失误损伤性能。
规则十二:删除重复脚本。
规则十三:配置ETag。说起这个不得不说条件请求If-Modified-Since和If-None-Match,都是用来进行缓
存再验证。ETag的问题是服务器构造ETag时,尽管两个文件完全一样,但如果处于不同的服务器的话还是会有
不同的ETag,增加了HTTP进行请求下载的次数,这对于后台是服务器集群的网站性能损伤很大。
规则十四:使Ajax可缓存。虽然Ajax是异步的,但也不能让等待响应的时间过长。优化准则的话参见上面的性能
准则,其中善用缓存依然是我们重点关注的
这本书总结起来主要是以下个方面的优化:
1.减少HTTP请求
2.页面内部优化
3.启用缓存
4.减少下载量
5.网络连接上的优化
减少HTTP请求
为什么减少HTTP请求可以提高Web性能?
先了解当浏览器向服务器发送一个http请求知道获取数据都经历哪些过程:
开启一个链接(tcp/ip的三次握手过程) -》 发送请求 -》 等待(网络延迟跟服务器的处理时
间)-》 下载数据
我们看一下百度首页中的http请求在各阶段耗费的时间,上面不同的颜色代表下图中的不同阶段:
关于http额外扩展:
可以关注到http所有请求除了图片之外,其余大部分http请求的事件花在了建立连接与等待阶段。
简单来说三次握手就是一个身份确认的过程。
实例讲解关于http额外扩展:
从前端的角度来说我已经做了如下优化: css、js合并压缩、图片压缩、雪碧图、静态资源全部上CDN。
但是依然很慢,实在是困惑,通过chrome的timeline分析,发现有些请求确实很慢,但是大部分时间
消耗在stalled阶段。如下图:
什么是stalled呢?
也即是从TCP连接建立完成,到真正可以传输数据之间的时间差。
先让我们要分析TCP连接为什么要等待这么久才能用?
用Wireshark抓包发现(如下图),TCP连接过程中有多次重传,直到达到最大重传次数后连接被客户端重置。
为什么会发生重传呢?
TCP三次握手后,发送端发送数据后,一段时间内(不同的操作系统时间段不同)接收不到服务端ACK包,就
会以 某一时间间隔(时间间隔一般为指数型增长)重新发送,从重传开始到接收端正确响应的时间就是
stalled阶段。而重传超过一定的次数(windows系统是5次),发送端就认为本次TCP连接已经down掉了,
需要重新建立连接。 对比以下,没有重传的http请求过程。如下图:
总结一下:stalled阶段时TCP连接的检测过程,如果检测成功就会继续使用该TCP连接发送数据,如果检测失
败就会重新建立TCP连接。所以出现stalled阶段过长,往往是丢包所致,这也意味着网络或服务端有问题。
由此我们可以得出结论:一个http请求绝大多数的时间消耗在了建立连接跟等待的时间,优化的方法是减少http请求。
(一)一般来说要减少http请求通常从两个方面下手:减少图片的请求、减少脚本文件和样式表的请求。
1.图片的减少通常有两种方式:css sprites、IconFont、内联图片。
CSS Sprites:将html元素的背景图片放到sprites 图片中的期望位置上。
IconFont:图标字体,这是近年来新流行的一种以字体代替图片的技术。它可以适应任何分辨率而不会出现
图片模糊问题,与图片相比它具有更小的容量,更高的灵活性(像字体一样可以设置图标大小、颜色、透明
度、hover状态、反转等),IE8以上的浏览器都支持该技术。
内联图片:通过使用data:URL模式可以再页面中包含图片而无需任何额外的请求。缺点就是IE8以下的浏览器不
支持这种方式,而IE8在数据大小上有限制,只能支持23kb以内的数据。对于较小的图片来说可以直接内联到web
页面中,但对于大图片内联到页面里会导致页面变大,聪明的做法是使用css,将内联的图片作为背景使用,并放
到外部样式表中,这意味着数据可以缓存在样式表内部。使用外部样式表虽然增加了一个http请求,但样式可以被
浏览器缓存,得到额外的收获。另外一点需要注意:base64是有损压缩。
2.减少脚本与样式表的请求主要原则就是合并。
在实际开发中我们遵循模块化的原则将代码分散到许多小文件中,按照软件开发的原则这是完全正确的,但对于上线
页面来说,每一个文件都会产生一个http请求,严重影响性能。和css sprites一样,将这些小文件合并到一个文
件中,可以减少http请求的数量并缩短最终用户响应时间。在合并过程中我们还需要使用工具精简(移除不必要的字
符以减小文件大小缩减下载时间)和混淆(除了移除不必要字符外,还会改写源代码,比如函数和变量名使用更短的
标量名)Javascript代码。目前最常用的前端构建工具就是glup(gulp 打包 require.js 模块依赖)。
这里有一篇另外扩展的文章参考:6-1-1节文章
引言
前端的高性能部分,主要是指减少请求数、减少传输的数据以及提高用户体验。许多网站的美化,
都是靠绚丽的图片达到的,图片恰恰是占用带宽的元凶。每个 img 标签,浏览器都会试图发起
一个下载请求。本文就详细介绍了图片优化的几种方式,介绍了使用的工具以及优化后的结果。
二.图片压缩 减少图片的大小,可以明显的提高性能,而对于已有图片,要想减少图片的大小,只能改变图
片的格式,这里推荐的是 PNG8 的格式,它可以在基本保持清晰度的情况下,减少图片的大
小。知道这个原理以后,可以用 Windows 的画图工具、以及 PhotoShop 工具逐个的改变。
但是这样做的缺点是单张处理,效率太慢。本文推荐一个在线转换工具 Smush.it,可以批量
的进行压缩与转换。它的地址是:www.smushit.com/ysmush.it。打开后效果如下图所示。
图 1. Yahoo 提供的在线压缩工具
我们上传了一张大小为 3790K 的图片,待在线程序处理完毕后,点击 Download Smushed
Images 下载查看结果。下载界面如下图所示。
图 2. 压缩后的结果
打开下载下来的压缩包,查看结果可以看到,图片从 3790 减少到了 3344,就如下图所示。
对于大批量的图片网站,这个方法会帮助快速实现批量图片压缩。
图 3. 压缩后的结果