时间:2021-07-01 10:21:17 帮助过:8人阅读
网站前端和后台性能优化的34条宝贵经验和方法,相关网页技术人员,需要注意的地方。
1 减少HTTP请求数量 (Minimize HTTP Requests)
tag:content
80%的用户响应时间被花费在前端,而这其中的绝大多数时间是用于下载页面中的图片、样式表、脚本以及Flash这些组件。减少这些组件的数量就可以减少展示页面所需的请求数,而这是提高网页响应速度的关键。
朴素的页面设计当然是减少组件的一种途径,但有没有能兼顾丰富的页面内容和快速的响应速度的方法呢?下面就是一些不错的技巧,能在提供丰富的页面展现的同时,减少Http请求数量:
合并文件,通过把所有脚本置于一个脚本文件里或者把所有样式表放于一个样式表文件中,从而减少Http请求的数量。当不同页面需要应用不同的脚本或样式时,合并这些文件会是一个很大的挑战,不过在发布网站时进行这种合并,将是提高网站响应速度的重要一步。
CSS Sprites是减少图片请求的首选方案。把所有的背景图片合并到一张图中,使用CSS的background-image 和background-position 属性去控制展现恰当的图片区域。
Image maps把多张图片组合成为一张图片。图片的总大小是不变的,但减少Http请求数会提高页面的响应速度。Image maps只能用于图片在网页中相邻的情况,比如导航条。制定image maps中的图片坐标是个很麻烦的过程,而且容易出错。同时给导航使用image maps也并不易读,所以并不推荐使用。
内联图片使用data: URL scheme 把图片数据嵌入页面,但这会增加Html文档的大小。把内联图片合并到你被缓存的的样式表中是一个能既减少HTTP请求数又不会增加页面大小的方法。但目前并不是所有的主流浏览器都支持内联图片。
减少页面的Http请求数量是第一步,而且对于提高用户初次访问体验是最重要的一步。正如在 Tenni Theurer的blog中的Browser Cache Usage - Exposed!里描述的,每天,有 40%-60%的访客并没有你的网站的缓存文件。提高这些初次访客的访问速度是提高用户体验的关键。
2 使用内容分布式网络 (Use a Content Delivery Network)
tag:server
用户连接你的网站服务器的速度影响响应的快慢。把你的网站布置在多台分布于不同地域的服务器上,会让用户觉得你的页面加载速度更快。那么我们应该从哪里开始呢?
不要一开始就把重新设计你的网站使其能够适应分布式结构作为实现网站地域分布的第一步。根据你的网站的复杂程度不同,更新网站结构的过程也许会包含诸如同步会话状态、在服务器间复制数据库等一系列复杂的步骤。这样你提高用户访问速度的目的反而会被更新网站架构的工作耽误。
记住,用户80-90%的访问时间被花费在下载页面中的图片、样式表、脚本、Flash这些组件上。这是网站展示的黄金法则。那么与其重新设计网站的结构,不如先实现这些静态组件的分布。这不仅仅可以大幅减少响应时间,而且由于内容分布式网络(content delivery networks)的存在,这将是个很简单的工作。
内容分布式网络(CDN)是一系列分布在不同地域的服务器的集合,能够更有效的给用户发送信息。它会根据一种衡量网域距离的方法,选取为某个用户发送数据的服务器。比如,到达用户最少跳或者最快相应速度的服务器会被选中。
一些大型Internet公司拥有他们自己的CDN,但使用公用的CDN服务提供商更为划算,比如 Akamai Technologies, Mirror Image Internet, 或者Limelight Networks。对于刚起步的公司和个人网站来说,CDN服务的花费也许会偏高。但当你的目标用户越来越多而且趋于国际化,用CDN来降低响应时间就很必要了。在Yahoo!,把静态的内容从自己的网络服务器移到CDN提高了用户20%甚至更多的访问速度。转向CDN会是一个只需要相对简单的代码更新的工作,而且那将会显著的提高你的网站访问速度。
3 给头部添加一个失效期或者Cache-Control (Add an Expires or a Cache-Control Header)
tag:server
这条法则包含两方面:
网页设计越来越丰富,页面里包含了越来越多的脚本、样式表、图片和Flash。页面的初次访问者也许会发送多个HTTP请求,但通过给头部添加失效期,你可以使那些组件被缓存。这会避免下次浏览页面时的不必要的HTTP请求。给图片文件的头部设置失效时间更为常用,但包括脚本文件、样式表和 Flash之类的所有组件的头部都应该被设置失效时间。
浏览器(还有代理服务器)使用缓存以减少HTTP请求的数量和大小,提高网页的加载速度。服务器在HTTP相应中通过头部中的过期时间告知客户端一个组件可以被缓存多久。下面是一个far future的过期头部,告诉浏览器这个响应直到2010年4月15日才会过期:
Expires: Thu, 15 Apr 2010 20:00:00 GMT
如果你使用的是Apache服务器,使用ExpiresDefault 指令会设置一个相对于当前时间的过期时间。这里有一个通过ExpiresDefault 指令把过期时间设为请求时间之后10年的例子:
ExpiresDefault "access plus 10 years"
记住,如果你使用了far future过期头部,你必须在组件更新时更换它的名字。在Yahoo!我们通常在建设网站的过程中执行这样的步骤:组件的名字里包含了它的版本,比如:yahoo_2.0.6.js。
使用一个far future过期头部只会在用户已经访问你的网站之后起作用。它不会影响一个没有缓存的初次访问者的HTTP请求数量。所以这一切的效果取决于多少用户访问页面时有一份预缓存(一份"预缓存"中已经包含了页面的所有组件)。我们对此在Yahoo!做过测试,发现拥有预缓存的用户在 75-85%。给头部添加far future失效期,可以增加浏览器缓存的组件数量并重复用于随后的页面浏览而不需要通过用户的网络发送哪怕一个字节。
4 Gzip压缩组件(Gzip Components)
tag:server
前台工程师的决策能够显著的减少在网络上传输 HTTP请求和响应花费的时间。确实,终端用户的带宽速度、Internet服务提供商和连接交换机的服务器这些因素都是开发小组所不能控制的。但还有一些其它因素会影响响应的时间,比如压缩文件,就会减少HTTP响应的大小从而减少响应的时间。
从HTTP/1.1开始,Web客户端就被设定为支持HTTP请求的头部中Accept-Encoding指定的压缩格式:
Accept-Encoding: gzip, deflate
当服务器检测到请求头部中的这一代吗,它就会使用客户端提供的方法列表中的一个来压缩响应内容。而服务器通过响应头部中的Content- Encoding来告知客户端它所使用的压缩方式:
Content-Encoding: gzip
Gzip是当前最常用也是最有效的压缩方式,GNU项目开发了这一方法并且符合RFC 1952标准。另外一种你可能见过的压缩格式是deflate,但它没有那么有效和常用。
使用gzip压缩通常会减少70%的响应大小。当前浏览器中大约90%的Internet通讯传输声明支持gzip。如果你使用Apache服务器,配置gzip的模块取决于服务器的版本:Apache 1.3 使用mod_gzip ,而Apache 2.x 使用mod_deflate。
浏览器和代理会有一些已知的问题,可能导致浏览器的预期内容和获得的实际压缩内容不匹配。幸运的是,这种情况随着旧浏览器的使用者减少而减少。 Apache的模块可以通过自动添加适当的变化响应文件头来解决这些问题。
服务器会根据文件类型选择gzip压缩的内容,但一般情况下,服务器选择压缩的内容会过于局限。大部分网站会压缩它们的Html文档,而压缩脚本和样式表也是值得一做的,但很多网站并没有这样做,事实上,压缩在包括 XML和JSON在内的任何文本响应都是值得的。图片和PDF文件不应该被gzip压缩,因为它们已经是被压缩了的文件,gzip它们不仅浪费CPU甚至还有增大文件大小的可能。
Gzip尽可能多的文件类型是减少页面大小从而提高用户体验的一个简单的方法。
5 把样式表放在前面(Put Stylesheets at the Top)
tag:css
在研究Yahoo!的性能时,我们发现把样式表挪到文档的头部可以让页面的加载显得更快。因为把样式表放在头部可以让页面逐步呈现。
关心网站性能的前台工程师通常希望页面能够逐步加载;即,我们希望浏览器能够把已经获得的内容尽快展现。这对于内容很多的页面以及网络连接较慢的用户尤为重要。给予用户视觉上的反馈(比如进度提示)的重要性,已经经过了很详尽的论证。而对于我们来说,Html 页面本身就可以作为进度提示!当浏览器逐步加载页面时,头部、导航条、顶部的logo等等这些都可以作为对正在等待页面的用户的可视的反馈。而这会从整体上提高用户体验。
把样式表放在文档的最后,会导致包括IE在内的大部分浏览器不进行逐步呈现。浏览器为了避免当样式改变时重绘元素而中止呈现。用户会十分无聊的看到一个空白的页面。
Html规范明确规定样式表应该被包含在页面的HEAD中:“和A不同,LINK只能在文档的HEAD部位出现,但它可以出现多次。”空白的屏幕或者由于没有应用样式而引起的内容的闪现都不值得去尝试。最好的方法是遵循HTML规范,把样式表放在文档的HEAD部位。
6 把脚本放在最后(Put Scripts at the Bottom)
tag:javascript
脚本可能会堵塞并发的下载。HTTP/1.1规范建议浏览器在每个域名下只进行两个并发下载。如果你把图片放在多个域名下,可以实现多于两个的并发下载。当脚本被下载时,即使使用不同的域名。浏览器也不会进行任何其它的下载。
有些情况下把脚本放到底部并不太容易。比如,脚本使用了document.write 来添加部分页面中的内容,就不能放到页面中更后面的位置。还可能有作用域的问题。很多情况下,还有一些变通的方法。
通常的建议是使用延迟脚本。DEFER属性表明脚本不包含document.write,而且提示浏览器继续展现。不幸的是,Firefox不支持DEFER属性。IE中,脚本可以被延迟,但并不如你期望的那么久。如果一个脚本可以被延迟,那么它也可以被放在页面的底部。这会让你的页面加载的更快。
7 不使用CSS表达式 (Avoid CSS Expressions)
tag:css
CSS表达式是一种有力的(同时也很危险的)动态设置CSS属性的方法。从IE5开始支持CSS表达式。比如,使用CSS表达式可以实现背景颜色每小时变换的效果。
background-color: expression_r( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" );
如上所示,表达式方法采用了 Javascript的表达。CSS属性则被设为Javascript表达式的结果。其它的浏览器会忽略CSS表达式,所以对于设置专属IE的属性以便在不同浏览器间能有一致的体验是有用的。、
而CSS表达式的问题是它比大多数人期望的执行次数更频繁。表达式不仅仅在页面展现和重新设置大小的时候执行,在页面滚动,甚至用户在页面上挪动鼠标时都会执行。给CSS表达式添加一个计数器可以跟踪CSS在什么时候和怎样执行。在页面上移动鼠标可以轻易的产生一万次以上的执行。
使用一次性的表达式是减少CSS表达式的执行次数的一个方法,当表达式第一次执行时,CSS表达式会被一个确定的值代替。如果在页面生命周期中,样式属性必须动态的设定,使用事件处理替代CSS表达式是一个可选的方法。如果必须使用CSS表达式,要记得它们会执行上千次并影响页面的性能。
8 使用外部的JavaScript和CSS (Make JavaScript and CSS External)
tag:javascript,css
很多性能规则都是解决怎样处理独立的组件的问题的。但是,考虑这些之前,你应该先考虑一个更基本的问题:JavaScript和CSS应该被放于外部的文件,还是内联在页面里?
在实际应用中使用外部的文件往往产生更快的页面,因为浏览器会缓存JavaScript和CSS文件。而内联在页面里的JavaScript和CSS会在每次请求页面时下载。这会减少所需的HTTP请求数,但增大HTML文档的体积。而另一方面,如果放在外部文件里的JavaScript和CSS被浏览器缓存,则既不用增加HTTP请求的数量,HTML文档的体积也会减少。
关键的问题是,外部的JavaScript和CSS的组件被缓存的频率和HTML文档被请求的次数相关。虽然很难去量化,但可以被用很多指标衡量。如果你的网站的用户在每个会话中浏览了很多网页而且很多页面重用了相同的JavaSctipt和样式表,缓存外部文件是有很大潜在的好处的。
很多网站都符合这样的指标。对于这些网站来说,最好的解决方案是把JavaScript和CSS发布为单独的文件。唯一的例外,对于主页,内联的文件更好一些,例如 Yahoo!'s front page 和 My Yahoo!。主页在每个会话中只有很少浏览(也许只有一次),你会发现内联的 JavaScript和CSS会让终端用户的响应更快。
对于有很多页面浏览量的首页来说,有很多能平衡内联文件所提供的HTTP请求减少的效果与外部文件缓存获得的好处的技巧。一种这样的技巧就是把JavaScript和CSS内联在说夜里,但在页面完成加载时动态下载外部文件。随后的页面会调用浏览器中已经缓存的外部文件。
9 减少DNS的查询 (Reduce DNS Lookups)
tag:content
正如电话簿使人名和他们的电话号码相对应,域名系统(DNS)能够使域名和IP地址相对应。当你在浏览器中键入http://www.yahoo.com,浏览器链接的DNS解析器会返回服务器的 IP地址。域名解析会耗费一些时间,DNS查找给定域名的IP地址一般会耗费20-120毫秒。在DNS查找结束前,浏览器不会从目标域名那里下载任何东西。
DNS查询会被缓存以便优化性能。会有一个专门的缓存服务器进行缓存,用户的ISP或者本地网络会维护它,但独立用户的电脑里也会有缓存。DNS信息存在于操作系统的DNS缓存里(微软Windows操作系统里的“DNS客户服务”)。大部分浏览器有它们自己的缓存,与操作系统的缓存相独立。当浏览器在自己的缓存里保存了DNS的记录,它不会向操作系统发出请求记录的要求。
IE默认缓存DNS查询30分钟,在的DnsCacheTimeout的键值中设定。Firefox则缓存DNS查询一分钟,在配置network.dnsCacheExpiration 中设定。(Fasterfox 将它变为一小时。)
当客户端的DNS缓存被清空(包括浏览器和操作系统的缓存),DNS查询的数量等同于网页中单独的域名的数量。包括页面中的链接,图片,脚本文件,样式表,Flash对象等。减少不同域名的数量则会减少DNS查询的数量。
减少不同域名的数量可能减少页面并行的下载数量。减少 DNS查询缩短了响应时间,但减少了并行下载数也许会增加响应时间。我的建议是将组件分布在两到四个域名之间。这能很好的折中减少DNS查询提高的速度和维持较高水平的并行下载的效果。
10 缩小JavaScript和CSS (Minify JavaScript and CSS)
tag:javascript,css
缩小是指从代码中删除不必要的字母,减少文件体积从而提高加载速度。缩减代码时需要移除所有的注释,以及不需要的空白(空格,新行和tab)。这样处理JavaScript之后,会由于下载文件的体积被减少而提高响应的性能。两个常用的缩减JavaScript代码的工具是JSMin 和YUI Compressor。YUI compressor也可以压缩CSS。
代码混淆是另一个可用于源代码的优化方案。它比压缩更为复杂,而且在混淆的过程中更容易产生 Bug。纵观U.S.的前十大网站,压缩获得了21%的体积减小而代码混淆达到了25%。虽然代码混淆的压缩程度更高,但压缩JavaScript的风险更小。
不仅仅要压缩外部的脚本和样式表,内敛的