原文译自雅虎开发者社区,转载译文请标明出处。
关注我的sina微博,共同进步!
为了让网页响应速度更快Exceptional Performance团队列出了一系列的最佳实践,包括35个最佳实践条目,分成7种类型类。
避免重定向
标签:内容
使用301和302状态码可以完成重定向。这里有个301响应的HTTP报文头部实例:
HTTP/1.1 301 MovedPermanently
Location: http://example.com/newuri
Content-Type: text/html
浏览器自动的将用户引导到location字段所指定的URL地址。所有的重定向的必要信息都位于报文头部,报文体通常为空。301和302响应并不被缓存除非添加像Expires或者Cache-Controll的报文头部以指定浏览器需要进行缓存。Meta刷新标签和JavaScript是其他的将用户引导到不同URL地址的方法,但是如果你必须重定向,更好的方式是使用3xx的HTTP状态码,这样可以确保浏览器返回按钮工作正常。
需要关注的是重定向减慢了用户的体验。将重定向插入到用户和HTML文件中会减慢页面中的一切,这是由于直到HTML文档完成加载,页面中没有可以被渲染的东西也没有组件开始被渲染。
一个经常发生的耗费的重定向并且却通常会被开发者疏忽的问题如下。URL地址末尾本该有的斜线丢失时就会出现这种问题,例如,访问http://astology.yahoo.com/astrology 会导致301响应的发生,将页面重定向到http://astology.yahoo.com/astrology/(注意添加了斜线)。在Apache中通过使用Alias或者mod_rewrite或者DirectorySlash来修正。
连接遗留网站到一个新的网站是重定向的另一个应用。其他的情况包括连接网站中不同的部分和基于特定的条件(浏览器类型,用户账户)将用户引导开。使用重定向来连接两个网站是件容易的事并且需要很少的额外编码。尽管在这些情况下使用重定向减少了开发者的工作量,这也降低了用户的体验。可选的方式是当两套编码位于同一个服务器上时,使用Alias和mod_rewrite来完成重定向。如果是因为域名更改而需要重定向,一个可选的方法是创建CNAME记录(创建别名从一个域名指向另一个域名的DNS记录)结合Alias和mod_rewrite来实现。
移除重复的脚本文件
标签:JavaScript
在一个页面中包含同样的JavaScript代码两次会降低性能。你想这种事情可能并不常发生。在对美国前十的网站的一个检查是发现他们中的两个包含重复的脚本文件。两个主要的因素增加了单页面中脚本文件重复的偶然性:团队规模和脚本文件的个数。当这样的是发生时,重复的脚本元素通过创建不必要的HTTP请求以及浪费JavaScript的执行资源来降低性能。
不必要的HTTP请求会在IE中发生,然而在Firefox中却没有。在IE中,如果外联的脚本文件被包含两次并且未被缓存,IE就在页面渲染的过程中产生两个HTTP请求。即使脚本文件被缓存了,额外的HTTP请求在页面重新加载的过程中也会发生。
除了产生不必要的HTTP请求,脚本的多次执行也浪费了时间。多余的JavaScript执行会在IE和Firefox中同时发生,而不管是否缓存。
一个避免意外的包含两次同样的脚本的方法是实现你的模板系统中的脚本管理模块。典型的方法是在HTML页面中使用Script标签。
<script type=”text/javascript”src=”menu.js”></script>
在PHP中可以借助于调用insertScript函数来实现
<?php insertScript(“menu.js”)?>
除了防止同脚本文件被插入两次,这个函数可以处理其他的脚本问题,比如依赖检查以及为脚本的文件名中添加版本号以支持长时间过期的头部(ExpiresHeader)。
配置ETags
标签:服务器端
实体标签(ETags)是web服务器和浏览器用来判断缓存中的组件和源服务器中的组件是否匹配的机制。(“entity”是“component”的另一种表述:图像,脚本,样式等)ETags通过提供比last-modified日期更富有弹性的机制来验证实体。一个Etag就是一个唯一标示一个组件版本的字符串。唯一的格式限制是这个字符串必须使用引号来标注。源服务器通过ETag响应报文头部来指定组件的ETag。
HTTP/1.1 200 Ok
Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT
ETag: “10c24bc-4ab-457e1c1f”
Content-Length: 12195
稍后,如果浏览器不得不验证组件,将使用If-None-Match头部将ETag传回到源服务器。如ETag匹配,304状态码将会被返回也就减少了响应报文12195字节。
GET /i/yahoo.git HTTP/1.1
Host: us.yimg.com
If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT
If-None-match: “10c24bc-4ab-457e1c1f”
HTTP/1.1 304 Not Modified
ETags的问题在于它们使用特殊属性来构建,使得它们只对应于一个特定的服务器。当从一个服务器上得到一个源组件稍后又从另一个不同的服务器上去验证的情况下,ETag是不会匹配的,这种情况在使用服务器集群处理请求的Web站点中是很普遍的现象。默认情况下,Apache和IIS都为ETag嵌入了数据奇迹般的较少了验证过程中的奇怪特性,这在基于多个服务器上的web站点上测试可行。
Apache1.3和2.x上ETag格式是inode-size-timestamp,尽管在多个服务器上会处于同一个目录下、有着同样的尺寸、许可、时间戳等。inode却随着不同的服务器而不同。
II5.0和6.0在ETags上有相似的问题。ETags在IIS上的格式是:Filetimestamp:ChangeNumber。“ChangeNumber”是用于记录对IIS的配置改变。在一个Web站点的所有的IIS服务器上,ChangeNumber一般是不同的。
结果就是由Apache和IIS为一个相同的模块产生的ETags在不同的服务器上并不匹配。如果ETags不匹配,用户也就不会获得简短快速的304响应,而那恰恰是ETags被设计出目的;取而代之的是他们将会获取一个正常的200响应,这个响应携带了所有的组件数据。如果你仅仅在一个服务器上管理你的站点,这不是问题。但是如果你有多个服务器来管理站点,并且使用Apache和IIS的默认ETag配置,你的用户就获得了更慢的页面加载,你的服务器负荷也会加重,你浪费了更多的带宽,并且代理也不会很好的缓存你的内容。即使你的组件有长时间过期的头部,一个有条件GET请求也会发出无论用户是点击了重新加载或者刷新按钮。
如果你没有利用ETags所提供的所有的弹性验证模型,最好直接移除ETag机制。Last-Modified头部依据组件的时间戳来验证。移除ETag会在相应报文和后续的请求中减少了HTTP头部的大小。这篇MicrosoftSupport文章介绍了如何移除ETags。在Apache中,在配置文件中仅仅加入下面这句话就能移除ETags:
FileETag:none
让Ajax请求可被缓存
标签:内容
Ajax的一个广为人知的好处就是它为用户提供了即时的反馈,因为它异步的从后端服务器上加载信息。然而使用Ajax可能使得用户为了等待异步的JavaScript和XML响应而开始把玩他的大拇指,用户是否一直等待取决于Ajax如何被使用。例如,在一个基于Web的邮件客户端中,用户一直等待Ajax的请求结果从而找到他们想要查询的Email信息。记住异步并不意味着实时。
为了提升性能,优化Ajax的响应至关重要。最重要的一个途径是将请求结果缓存起来,就像在“添加Expires和Cache-Contoll”一节中讨论的那样。一些其他的规则也适用于Ajax:
Gzip压缩组件
减少DNS查询
压缩JavaScript
避免重定向
配置ETags
让我们看看一个例子。一个Web2.0的邮件客户端或许自动使用Ajax来加载用户的地址簿。如果自从上次使用email web程序以来,用户没有改变地址簿,之前的地址簿响应数据可以从缓存中读取,前提是Ajax缓存通过使用Expires或者Cache-Contolle头部实现。浏览器必须被通知什么时候使用之前的缓存地址簿数据或者请求新的数据。这可以通过为地址簿的Ajax地址添加时间戳来标注最后一次用户更改地址簿的时间,从而实现上述目的,例如&t=1190241612。如果地址簿自从上一次加载以来没有被改变,时间戳不变,浏览器会从缓存中获取地址簿数据从而减少了一个HTTP往返请求。如果用户改变了地址簿数据,时间戳确保一个新的URL地址和缓存中的响应不同,浏览器就向更新的地址簿入口请求数据。
尽管Ajax响应报文被动态的创建,但仅仅对单户起作用,他们可以被缓存。这将使你的Web2.0应用的更快。
尽早的清除缓存
标签:服务器端
当用户请求页面,无论如何需要200-500ms的时间让后端服务器生成一个页面。在这个时间内,浏览器因为等待数据的到大而处于空闲的状态。在PHP中有flush函数。它能够将部分准备好了的HTML响应发送给浏览器,使得浏览器可以开始加载组件而你的后端服务器忙于生成其他的HTML页面。在忙碌的后端和松闲中都可以看到这样做的好处。
一个添加好的flushing的地方就在HEAD标签后,因为html的Head标签通常容易生成,并且允许包好任何的CSS和JavaScript文件,这样浏览器开始并行请求数据而后端仍然在处理其他的东西。
例如:
…<!—css, js-->
</head>
<?php flush();?>
<body>
…<!—content-->
Yahoo! Search主导了这方面研究并且在真实的用户上进行测试,从而证明使用这项技术的好处。
用GET发送AJAX请求
标签:服务器端
Yahoo!Mail团队发现当使用XMLHttpRequest时,POST在浏览器中经历了两个步骤的处理:先发送请求头部,然后发送数据。所以最好使用GET,仅仅使用一个TCP数据包发送请求(除非你有很多的cookies)。在IE中最大URL长度是2K,如果发送多于2K的数据,你就不能使用GET。
一个让人感兴趣的个例是POST如果没有发送任何数据的时候的行为类似于GET。基于HTTP的规范,GET为的是获取信息,所以在仅仅只是请求数据的时候使用GET是有意义的(从语义上),而和向服务器端发送数据则不同。
延迟加载模块
标签:内容
你可以仔细看下你的页面,问问自己:“为了完成页面的起始渲染,哪些是绝对需要的?”其余的内容和组件可以稍后加载。
JavaScript是很适合置于onload事件触发之前或之后。例如,如果你使用JavaScript或者库来完成拖动和动画的任务,这些可以等待。因为在页面上拖动元素在初始渲染之后才可用。其他的可以在加载事件之后获取的包括隐藏的内容(在用户的某个操作后出现的内容)或者图片折叠。
有些工具可以帮助你达成目的:YUI Image Loader允许你延迟加载位于折叠区域之后的图片并且YUIGet Utility是一个简单的方法来实时加载JS和CSS。例如可以使用Firebug面板看看Yahoo!Home Page的加载状况。
当性能目标和其他的web开发最佳实践相关联时。这种情况下,渐进增强的方法告诉我们JavaScript可以提升用户体验,但是你不得不确认页面在没有JavaScript的情况下也是可用的。所以当你确认页面工作良好,你可以通过一些后加载的脚本提升页面,随后当你的拖动效果和动画效果发挥效应时会给你带来跟多的喝彩。
继续阅读:高性能网站建设的最佳实践(三)
原文译自:http://developer.yahoo.com/performance/rules.html
转载于:https://blog.51cto.com/moviejs/1305404