Web性能优化:What? Why? How?

为何要提高web性能?css

Web性能黄金准则:只有10%~20%的最终用户响应时间花在了下载html文档上,其他的80%~90%时间花在了下载页面组件上。html

  web性能对于用户体验有及其重要的影响,根据著名的`2-5-8`原则:前端

  • 当用户在2秒之内获得响应,会感受系统的响应很是快
  • 当用户在2-5秒以内获得响应,会感受系统的响应速度还能够
  • 当用户在5-8秒以内获得响应,会感受系统的响应很是慢,但还能够接受
  • 当用户在8秒以后都没有获得响应,会感受系统糟透了,甚至系统已经挂掉;要么打开竞争对手的网站,要么从新发起第二次请求

  凡事都须要研究,经过科学的研究咱们就能够找到事物的发展规律。这里要感谢雅虎的工程师总结的14条前端优化法则,使得咱们能够站在巨人的肩膀上。《高性能网站建设》这本书中的14条优化原则,总结起来主要是如下个方面的优化:java

  1. 减小HTTP请求
  2. 页面内部优化
  3. 启用缓存
  4. 减小下载量
  5. 网络链接上的优化

  

为何减小HTTP请求能够提升Web性能?web

  要回答这个问题,咱们就要了解当浏览器向服务器发送一个http请求知道获取数据都经历哪些过程:express

  开启一个连接(tcp/ip的三次握手过程) -》 发送请求 -》 等待(网络延迟跟服务器的处理时间)-》 下载数据json

  咱们看一下百度首页中的http请求在各阶段耗费的时间,上面不一样的颜色表明下图中的不一样阶段gulp

  能够看到除了图片以外,其他大部分http请求的事件花在了创建链接与等待阶段。segmentfault

  http协议创建在TIC/IP协议之上,在TCP/IP协议中,TCP协议提供可靠的链接服务,采用三次握手创建一个链接。 简单来讲三次握手就是一个身份确认的过程:windows

  (第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求创建联机;)

晴儿:你是潇哥哥吗,我是晴儿

  (第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包)

潇剑:这货是谁,一箫一剑走江湖,下一句是什么?

  (第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则链接创建成功。)

晴儿:这首诗。。。你真的是潇哥哥,一萧一剑走江湖,千古情愁酒一回。。。

潇剑:晴儿,你真的是晴儿。。。。

(啪啪啪啪啪啪啪啪啪啪啪啪啪啪啪。。。。。。。。。。。。)

  言归正传,这个过程也是须要消耗时间的,在百度首页找到一个极端的例子:

  而等待的时间一般也大于内容下载的时间,这里一样找到一个极端例子:

  由此咱们能够得出结论:一个http请求绝大多数的时间消耗在了创建链接跟等待的时间,优化的方法是减小http请求。

 

如何提升web性能?

  一、减小HTTP请求

  通常来讲要减小http请求一般从两个方面下手:减小图片的请求、减小脚本文件与样式表的请求

  图片的减小一般有两种方式:css sprites、内联图片、IconFont。

  CSS Sprites:将多张图片合并成一幅单独的图片,使用css的background-position属性,将html元素的背景图片放到sprites 图片中的指望位置上。使用这项技术的附加优势是他下降了下载量,合并后的图片比分离的图片和更小,由于它下降了图片自身的开销(颜色表、格式信息等等)。实际项目中css sprites是一项体力活,由于开发过程当中须要对这张大图进行维护(添加、减小图片),张鑫旭同窗的文章中有介绍如何管理sprites图片能够做为参考(这里)。若是须要在页面中为背景、连接、导航栏提供大量的图片,css sprites绝对是一种优秀的解决方案(干净的标签、较少的图片、较短的响应时间)。

  内联图片:经过使用data:URL模式能够再页面中包含图片而无需任何额外的请求。缺点就是IE8如下的浏览器不支持这种方式,而IE8在数据大小上有限制,只能支持23kb之内的数据。对于较小的图片来讲能够直接内联到web页面中,但对于大图片内联到页面里会致使页面变大,聪明的作法是使用css,将内联的图片做为背景使用,并放到外部样式表中,这意味着数据能够缓存在样式表内部。使用外部样式表虽然增长了一个http请求,但样式能够被浏览器缓存,获得额外的收获。另一点须要注意:base64是有损压缩。

  IconFont:图标字体,这是近年来新流行的一种以字体代替图片的技术。它能够适应任何分辨率而不会出现图片模糊问题,与图片相比它具备更小的容量,更高的灵活性(像字体同样能够设置图标大小、颜色、透明度、hover状态、反转等),IE8以上的浏览器都支持该技术。在使用IconFont以前,你首先要肯定你选则的字体库是不是收费。详细内容能够参考这篇文章:图标字体化浅谈

  减小脚本与样式表的请求主要原则就是合并。在实际开发中咱们遵循模块化的原则将代码分散到许多小文件中,按照软件开发的原则这是彻底正确的,但对于上线页面来讲,每个文件都会产生一个http请求,严重影响性能。和css sprites同样,将这些小文件合并到一个文件中,能够减小http请求的数量并缩短最终用户响应时间。在合并过程当中咱们还须要使用工具精简(移除没必要要的字符以减少文件大小缩减下载时间)和混淆(除了移除没必要要字符外,还会改写源代码,好比函数和变量名使用更短的标量名)Javascript代码。对于采用AMD或CMD进行模块化开发的同窗,在合并过程当中一般会将依赖的其余模块打包到一个文件中,而模板html一般以字符串的方式内联到Javascript文件中。目前最经常使用的前端构建工具就是glup,这里有一篇初步应用的文章:前端 | gulp 打包 require.js 模块依赖

  

  二、页面内部优化

  关于页面内部优化主要方向:样式表放在顶部、脚本文件放在底部、避免css表达式、把脚本的样式表放在外部、移除重复脚本

  关心性能的工程师都但愿页面可否尽快的展示在用户面前,对于页面中不少内容的页面咱们都但愿内容可以逐步加载,为用户提供可视化回馈。而将样式表放在底部会致使浏览器阻止内容逐步呈现。为避免当页面变化时重绘页面元素,浏览器会阻塞页面呈现,直到样式表解析完毕(详细内容能够查看个人这篇博客)。因此若是将样式表放在顶部并不会减小资源的加载时间,它减小的是页面的呈现时间。小米主页曾经犯过这样的错误:

  将样式表放在底部会阻塞页面的逐步呈现,而将script文件放在页面顶部一样会阻塞页面的逐步呈现。script元素会阻塞后续内容的解析,由于script中能够同过document.write来更改页面。解决的办法就是将script标签放在页面底部。这样既可让内容逐步呈现,也能够提升下载的并行度。若是咱们肯定不须要document.write那能够为script标签加上asyn属性(Ie中要加上defer)提升并行下载度。

  CSS表达式是ie支持的能够用来动态更改css属性的一种方式,咱们不须要了解太多,她的书写方式以下,一旦在产品中发现expression关键字就要完全消灭。

  

  使用外部脚本和样式这一条,我想凡有点经验的工程师都会这么干。

  移除重复脚本:这条说的主要是避免在页面中屡次加入同一份Javascript代码,若是咱们的开发中有依赖管理的方式好比AMD、CMD,基本不会出现这种状况。

 

  三、启用缓存

  关于缓存的使用这里介绍两套方案:expires/If-Modified-Since、Cache-Control/Etag;前者是HTTP1.0中的缓存方案,后者是HTTP1.1中缓存方案,若http头部中同时出现两者,后者的优先级更高。

  If-modified-since的方式一般被称为条件Get。浏览器缓存中保存了一个文件的副本,但须要向服务器询问此副本是否可用。If-Modified-Since是浏览器将最后修改时间发送给服务器,服务器相应头中Last-Modified进行对比;若If-Modified-Since <= Last-Modified 则浏览器读取本地副本。此时响应状态为304 Not Modified, 并不在发送响应体。

  Expries:虽然使用条件GET和304响应可以节省时间,但浏览器跟服务器端仍然要发送一次请求进行确认。经过明确设置副本的过时时间能够避免条件GET。当浏览器发现响应头中的expires时,会将过时时间和文件一块儿保存到缓存中去。在过时以前一直从缓存中读取。expires头使用一个特定的时间来指定缓存的有效期,他要求浏览器与服务器时间彻底一致。并且一旦过时,服务器端配置中须要从新设顶一个过时时间。

  ETag(实体标签):是服务器用于检查浏览器缓存有效性的一种机制。ETag在HTTP1.1中引入,ETag是惟一标识了一个组件的一个特定版本的字符串。惟一的格式约束是这个字符串必须使用双引号。若是浏览器要验证一个组件是否有效他会使用If-None-Match将etag字符串传送给服务器。若是ETag是匹配的,服务器端会返回304.(若是实体数据须要根据User-Agent或Accept-Language来改变时,ETag提供了更高的灵活性)。对于使用服务器集群的网站来讲,从一台服务器到另外一台服务器,ETag一般是没法匹配的。这是ETag的问题。并且即使同时使用If-Modified-Since和If-None-Match也并不能达到预期效果。解决方法老是有的:自定义Etag格式

  

  Cache-Control:HTTP1.1引入了来代替Expires,它使用max-age指令来指定副本被缓存多久,该指令以秒为单位定义了一个更新窗,组件从被请求开始到如今的秒数小于设定值,则一直使用副本。避免了一次http请求。相比Expries,Cache-Control指令提供了更细粒度的控制。详细内容请看大额同窗的文章:透过浏览器看HTTP缓存

 

  四、减小下载量

  减小下载量最有效的方式就是开启gzip压缩,gzip是GNU开发的一种免费格式。压缩组件经过减少http响应的大小来加快响应速度。HTTP1.1经过使用Accept-Encoding来标识支持的压缩,若是服务器看到这个标识,会使用请求头中的一种方式来压缩响应。并经过Content-Encoding来通知web客户端。不少网站会压缩html文件,实际上包括xml跟json在内的任何文本均可以压缩,但图片和pdf不该该压缩。根据经验一般能够对大于1kb或2kb的文件进行压缩。压缩一般能将响应的数据量减小70%。压缩的成本在于:服务器须要耗费额外的cpu进行压缩,客户端须要解压缩。因此须要在cpu的消耗和数据块的大小之间进行取舍。

 

  五、优化网络链接

  网络链接的优化主要有三个规则:使用CDN加速、减小DNS查找、避免重定向

  CDN:CDN是地理上分布的web server的集合,用于更高效地发布内容。一般基于网络远近来选择给具体用户服务的web server。 这缩短了资源的传输响应时间,有效提升web性能。

  DNS用于映射主机名和IP地址,通常一次解析须要20~120毫秒。浏览器会首先根据页面的主机名进行域名解析,在有ISP返回结果以前页面不会加载任何内容,因此减小DNS查找能够有效下降等待时间。为达到更高的性能,DNS解析一般被多级别地缓存,如由ISP或局域网维护的caching server,本地机器操做系统的缓存(如windows上的DNS Client Service),浏览器。IE的缺省DNS缓存时间为30分钟,Firefox的缺省缓冲时间是1分钟。 咱们能作的是尽可能减小一个页面的主机名,但要在浏览器最大并行下载数跟dns查找之间作权衡。根据雅虎的研究,最好将主机名控制在2-4个内。

  重定向:将一个URL从新路由到另外一个URL。重定向功能是经过301和302这两个HTTP状态码完成的,如: 
   HTTP/1.1 301 Moved Permanently 
   Location: http://example.com/newuri 
   Content-Type: text/html 

  浏览器自动重定向请求到Location指定的URL上,重定向的主要问题是下降了用户体验。 种最耗费资源、常常发生而很容易被忽视的重定向是URL的最后缺乏/,致使自动产生结尾斜线的缘由是,浏览器在进行get请求是必须指定一些路径;若是没有路径它就会简单的使用文档根。(主机缺乏结尾斜线是不会发生重定向:http://www.baidu.com)缺乏结尾斜线发生重定向是不少web服务器的默认行为。须要在服务器端设置方可消除。如下图片是豆瓣的一个url请求:

 

  雅虎的14条优化规则在很长的一段时间里发挥着重要做用,随着技术的发展,单单这十四条原则已经不可以知足前端性能优化。在一些大公司出现了前端工程化这一律念,详细内容能够参考一下这篇文章:前端性能优化工程化进阶

 

  参考资料:

web前端性能意思、关注重点、测试方案、

WEB站点性能优化实践(加载速度提高2s)

HTTP协议三次握手过程

高性能WEB开发 - 为何要减小请求数,如何减小请求数!

我是如何对网站CSS进行架构的

图标字体化浅谈

利用ETag缓存优化请求

透过浏览器看HTTP缓存

Web应用性能优化黄金法则——转

http://www.cnblogs.com/dojo-lzz/p/4591446.html

相关文章
相关标签/搜索