提高网站访问速度的34条军规一

1 减少HTTP请求数量 (Minimize HTTP Requests)

tag:content

80%的用户响应时间被花费在前端,而这其中的绝大多数时间是用于下载页面中的图片、样式表、脚本以及Flash这些组件。减少这些组件的数量就可以减少展示页面所需的请求数,而这是提高网页响应速度的关键

朴素的页面设计当然是减少组件的一种途径,但有没有能兼顾丰富的页面内容和快速的响应速度的方法呢?下面就是一些不错的技巧,能在提供丰富的页面展现的同时,减少Http请求数量:

合并文件,通过把所有脚本置于一个脚本文件里或者把所有样式表放于一个样式表文件中,从而减少Http请求的数量。当不同页面需要应用不同的脚本或样式时,合并这些文件会是一个很大的挑战,不过在发布网站时进行这种合并,将是提高网站响应速度的重要一步。

CSS Sprites是减少图片请求的首选方案。把所有的背景图片合并到一张图中,使用CSS的background-imagebackground-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%的访客并没有你的网站的缓存文件。提高这些初次访客的访问速度是提高用户体验的关键。

 

11 避免重定向 (Avoid Redirects)

tag:content

 

重定向结束于301或302状态码。这里有一个301响应的HTTP头的例子:
      HTTP/1.1 301 Moved Permanently
      Location: http://example.com/newuri
      Content-Type: text/html

浏览器会自动把用户转向Location域中指明的Url地址。HTTP头里包含了重定向所需的所有信息。响应的主体一般是空的。301或者302响应都不会被实际缓存,除非添加额外的头部,比如 Expires或者Cache-Control指明了它应该被缓存。meta refresh标签和JavaScript也可以将用户重定向到不同的URL,但如果你必须执行重定向,最好的方法是使用标准的3XX HTTP状态代码,以便使后退按钮工作正常。

需要谨记的是,重定向降低了用户体验。在用户和HTML文档之间插入的重定向延误了页面的呈现和组件下载,因为它们都不可能在获得HTML文档之前开始。

一种最浪费性能的重定向频繁发生而网络开发者们却往往没有意识到,那就是当地址中应当有一个左斜线(/)却没有的时候。比如,访问http://astrology.yahoo.com/astrology会导致一个301效应并重定向到http://astrology.yahoo.com/astrology/(注意这里加了一个左斜线)。在Apache中,这可以使用mod_rewrite,或者在Apache事件处理中使用DirectorySlash指令来修补。

使用重定向的另一个常见场景是连接旧网站和新网站。还包括连接网站的不同部分,或者在不同情况下(比如依据浏览器的类型,用户的类型等)重定向用户。使用重定向来连接两个网站很简单而且需要很少的额外代码。虽然在这些情况下使用重定向减少了开发者的麻烦,但却降低了用户体验。如果两部分在同一个服务器上,可以使用Alias 和rewrite来替代重定向。如果域名变更引起了重定向,可以创建一个CNAME(一种可以创建一个别名使一个域名指向另一个的DNS记录)结合 Alias或者mod_rewrite来替代重定向。

 

12 移除重复的脚本 (Remove Duplicate Scripts)

tag:javascript

 

在同一个页面中包含两个相同的脚本文件降低了性能。这并不如你想象的那么罕见。在对美国十大网站中的检查中,发现它们中的两个包含了重复的脚本。有两个主要因素增加了一个页面包含两个相同脚本的几率——团队的大小和脚本的数量。当脚本被重复包含时,由于增加了不必要的HTTP请求和JavaScript的执行,影响了性能。

不必要的HTTP请求在IE中存在,而Firefox终没有。在IE中,如果一个外部脚本被包含了两次而且没有被缓存,在页面加载的过程中会产生两次HTTP请求。即使脚本被缓存了,当用户重载页面时,多余的HTTP请求也会发生。

产生多余的HTTP请求的同时,多次执行脚本也会浪费时间。在Firefox和IE中,无论是否被缓存,脚本都会被重复执行

避免脚本被意外加载两次的一个方法是在你的模板系统中执行一个脚本管理模块。通常的方式是在HTML页面中使用SCRIPT标签来添加一个脚本:
<script type="text/javascript" src="menu_1.0.17.js"></script>

HP中,可以选择创建一个叫做insertScript的方法:
<?php insertScript("menu.js") ?>

这个函数不仅仅能防止脚本被重复加载多次,还可以解决脚本的其他问题,比如独立性检测以及为脚本添加版本号码以应对far future Expires头部。

 

13 设定ETags (Configure ETags)

tag:server

 

实体标签(ETags)是服务器和浏览器用于确定浏览器中缓存的组件和服务器中的是否对应的一种机制。("entity"是组件的另一种说法:图片、脚本、样式表等等)添加ETags用于辨别组件提供了比单纯利用“最后修改时间”更为灵活的机制。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.gif 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

ETag的问题是它们往往在网站的一个服务器中被设为唯一的,当浏览器从一个服务器得到了组件并在稍后试图到另一个服务器验证时,ETag会不匹配,而这在使用多个服务器来处理请求的网站中是很常见的。默认情况下,Apache和IIS在ETag中嵌入的数据戏剧性的减少了应用多台服务器的网站的ETag验证成功几率。

Apache1.3和2.新版本的ETag格式是inode-size-timestamp。虽然一个给定的文件在多台服务器中处于同一个目录,而且有同样的大小,权限,时间戳,但它的inode在不同服务器中是不同的。

IIS5.0和6.0有同样的问题。IIS中ETag的格式是Filetimestamp:ChangeNumber。ChangeNumber用来跟踪IIS配置的改变次数。一个网站的所有IIS不可能有相同的ChangeNumber。

这导致的结果是,Apache和IIS对完全相同的组件产生的ETag在不同服务器间不能匹配。如果ETags不匹配,用户不会得到小而快的304响应,而是一个普通的200响应和组件的所有数据。如果你把你的网站放在了一个服务器里,这不会是一个问题。但如果你的网站有多台服务器,而且你使用了Apache和IIS默认的ETag配置,你的用户会访问页面的速度会变慢,你的服务器加载的程度更高,消耗了更大的带宽,代理服务器不能有效的缓存你的内容。即使你的组件有一个ar future Expires头部,当用户重载或者刷新页面时,依然会发送一个GET请求。

如果你不打算利用ETags提供的灵活的验证模式,你最好把ETag统统移除。Last-Modified头部的验证方式给予组件的时间戳。移除ETag同时减少响应和随后的请求中的HTTP头部大小。这篇微软的支持文档描述了怎样在IIS中移除ETags。在Apache中,你只要在Apache配置文件中添加如下一行:
     FileETag none

 

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

这条法则包含两方面:

  • 对于静态组件:把头部的缓存期设为某个遥远的未来,使其能够“永不过期”。
  • 对于动态组件:使用适当的Cache-Control头部帮助浏览器执行特定的请求。

网页设计越来越丰富,页面里包含了越来越多的脚本、样式表、图片和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( (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 pageMy 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代码的工具是JSMinYUI Compressor。YUI compressor也可以压缩CSS。

代码混淆是另一个可用于源代码的优化方案。它比压缩更为复杂,而且在混淆的过程中更容易产生Bug。纵观U.S.的前十大网站,压缩获得了21%的体积减小而代码混淆达到了25%。虽然代码混淆的压缩程度更高,但压缩JavaScript的风险更小。

不仅仅要压缩外部的脚本和样式表,内敛的<script>和<style>部分也可以而且应当被压缩。即使你gzip了你的脚本和样式,压缩它们仍然能减少5%以上的体积。随着JavaScript和CSS的应用和体积的增加,压缩你的代码获得的收益也会越来越多。

 

11 避免重定向 (Avoid Redirects)

tag:content

 

重定向结束于301或302状态码。这里有一个301响应的HTTP头的例子:
      HTTP/1.1 301 Moved Permanently
      Location: http://example.com/newuri
      Content-Type: text/html

浏览器会自动把用户转向Location域中指明的Url地址。HTTP头里包含了重定向所需的所有信息。响应的主体一般是空的。301或者302响应都不会被实际缓存,除非添加额外的头部,比如 Expires或者Cache-Control指明了它应该被缓存。meta refresh标签和JavaScript也可以将用户重定向到不同的URL,但如果你必须执行重定向,最好的方法是使用标准的3XX HTTP状态代码,以便使后退按钮工作正常。

需要谨记的是,重定向降低了用户体验。在用户和HTML文档之间插入的重定向延误了页面的呈现和组件下载,因为它们都不可能在获得HTML文档之前开始。

一种最浪费性能的重定向频繁发生而网络开发者们却往往没有意识到,那就是当地址中应当有一个左斜线(/)却没有的时候。比如,访问http://astrology.yahoo.com/astrology会导致一个301效应并重定向到http://astrology.yahoo.com/astrology/(注意这里加了一个左斜线)。在Apache中,这可以使用mod_rewrite,或者在Apache事件处理中使用DirectorySlash指令来修补。

使用重定向的另一个常见场景是连接旧网站和新网站。还包括连接网站的不同部分,或者在不同情况下(比如依据浏览器的类型,用户的类型等)重定向用户。使用重定向来连接两个网站很简单而且需要很少的额外代码。虽然在这些情况下使用重定向减少了开发者的麻烦,但却降低了用户体验。如果两部分在同一个服务器上,可以使用Alias 和rewrite来替代重定向。如果域名变更引起了重定向,可以创建一个CNAME(一种可以创建一个别名使一个域名指向另一个的DNS记录)结合 Alias或者mod_rewrite来替代重定向。

 

12 移除重复的脚本 (Remove Duplicate Scripts)

tag:javascript

 

在同一个页面中包含两个相同的脚本文件降低了性能。这并不如你想象的那么罕见。在对美国十大网站中的检查中,发现它们中的两个包含了重复的脚本。有两个主要因素增加了一个页面包含两个相同脚本的几率——团队的大小和脚本的数量。当脚本被重复包含时,由于增加了不必要的HTTP请求和JavaScript的执行,影响了性能。

不必要的HTTP请求在IE中存在,而Firefox终没有。在IE中,如果一个外部脚本被包含了两次而且没有被缓存,在页面加载的过程中会产生两次HTTP请求。即使脚本被缓存了,当用户重载页面时,多余的HTTP请求也会发生。

产生多余的HTTP请求的同时,多次执行脚本也会浪费时间。在Firefox和IE中,无论是否被缓存,脚本都会被重复执行

避免脚本被意外加载两次的一个方法是在你的模板系统中执行一个脚本管理模块。通常的方式是在HTML页面中使用SCRIPT标签来添加一个脚本:
<script type="text/javascript" src="menu_1.0.17.js"></script>

HP中,可以选择创建一个叫做insertScript的方法:
<?php insertScript("menu.js") ?>

这个函数不仅仅能防止脚本被重复加载多次,还可以解决脚本的其他问题,比如独立性检测以及为脚本添加版本号码以应对far future Expires头部。

 

13 设定ETags (Configure ETags)

tag:server

 

实体标签(ETags)是服务器和浏览器用于确定浏览器中缓存的组件和服务器中的是否对应的一种机制。("entity"是组件的另一种说法:图片、脚本、样式表等等)添加ETags用于辨别组件提供了比单纯利用“最后修改时间”更为灵活的机制。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.gif 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

ETag的问题是它们往往在网站的一个服务器中被设为唯一的,当浏览器从一个服务器得到了组件并在稍后试图到另一个服务器验证时,ETag会不匹配,而这在使用多个服务器来处理请求的网站中是很常见的。默认情况下,Apache和IIS在ETag中嵌入的数据戏剧性的减少了应用多台服务器的网站的ETag验证成功几率。

Apache1.3和2.新版本的ETag格式是inode-size-timestamp。虽然一个给定的文件在多台服务器中处于同一个目录,而且有同样的大小,权限,时间戳,但它的inode在不同服务器中是不同的。

IIS5.0和6.0有同样的问题。IIS中ETag的格式是Filetimestamp:ChangeNumber。ChangeNumber用来跟踪IIS配置的改变次数。一个网站的所有IIS不可能有相同的ChangeNumber。

这导致的结果是,Apache和IIS对完全相同的组件产生的ETag在不同服务器间不能匹配。如果ETags不匹配,用户不会得到小而快的304响应,而是一个普通的200响应和组件的所有数据。如果你把你的网站放在了一个服务器里,这不会是一个问题。但如果你的网站有多台服务器,而且你使用了Apache和IIS默认的ETag配置,你的用户会访问页面的速度会变慢,你的服务器加载的程度更高,消耗了更大的带宽,代理服务器不能有效的缓存你的内容。即使你的组件有一个ar future Expires头部,当用户重载或者刷新页面时,依然会发送一个GET请求。

如果你不打算利用ETags提供的灵活的验证模式,你最好把ETag统统移除。Last-Modified头部的验证方式给予组件的时间戳。移除ETag同时减少响应和随后的请求中的HTTP头部大小。这篇微软的支持文档描述了怎样在IIS中移除ETags。在Apache中,你只要在Apache配置文件中添加如下一行:
     FileETag none

 

14 让Ajax可以缓存 (Make Ajax Cacheable)

tag:content

 

Ajax的好处之一是它能给用户提供瞬间的响应,因为它从服务端异步请求数据。但Ajax不能保证用户在等候那些异步的JavaScript和XML响应返回时什么都不做。在应用程序中,用户是否继续等待取决于Ajax怎样应用。比如,在一个基于Web的Email客户端用户会等候Ajax返回他们所搜索的邮件信息。记住异步并不代表“即刻”。

为了提高性能,优化Ajax响应很重要。提高Ajax性能最重要的方式是使响应缓存,正如“添加一个过期期限和缓存控制头”这一节讨论的。这些原则同样适用于Ajax

  • Gzip组件
  • 减少DNS查询
  • 压缩JavaScript
  • 避免重定向
  • 设定ETag

我们看一个例子。一个Web2,0的邮件客户端可能会用Ajax自动下载用户地址簿。如果用户从上次使用邮件网站以来没有修改她的地址簿,那么如果Ajax响应使用了长期失效时间或者缓存控制头部,地址簿就可以从缓存中读取出来。浏览器必须被告知“使用之前的缓存地址簿”而不是“请求一个新的地址簿”。可以在地址簿Ajax的URL中添加一个标识用户最后一次修改地址簿的时间戳,比如,&t=1190241612。如果地址簿从最后一次下载后没有被更改,时间戳将相同而地址簿将会从浏览器的缓存中得到来替代额外的HTTP传输。如果用户更改了她的地址簿,时间戳会保证新的URL不会和缓存中的匹配,而且浏览器会请求会请求更新的地址簿记录。

即使你的Ajax响应时动态创建的,而且只适用于一个用户,它们依然会被缓存。这样做会让你的Web2.0应用程序更快。

 

15 更早的刷新缓冲区 (Flush the Buffer Early)

tag:server

 

当用户请求一个页面,服务端会花费200至500毫秒的时间组合HTML页面。在这期间,浏览器会静静等待数据到来。PHP中有flush()函数,它允许你向浏览器发送部分就绪的HTML响应,这样浏览器可以在服务器处理余下的HTML页面时去获取组件。这样的好处主要在忙碌的后台和轻松的前台间可以看到。

在HEAD后面是放置刷新操作的好地方,因为头部的HTML代码更容易产生,而且可以让你放置任何CSS和JavaScript文件,以便浏览器在后台工作依然进行时并行开始获取组件。

例子:

... <!-- css, js -->
</head>
<?php flush(); ?>
<body>
... <!-- content -->

Yahoo! search先行研究并且进行了真人测试证明了使用这项技术的好处。

 

16 在Ajax请求中使用GET方法 (Use GET for AJAX Requests)

tag:server

 

Yahoo! Mail 团队发现进行XMLHttpRequest的时候,POST方法在浏览器中分两步执行:先发送头部,然后发送数据。所以最好使用只发送一个TCP包(除非你有很多的cookie)的GET方法。IE中URL的最大长度是2000,所以如果你发送超过2000的数据就不能使用GET方法。

一个有趣的现象是,POST方法并不像GET那样实际发送数据(而Get则名副其实)。基于HTTP规范,GET方法意味着取回数据,所以当你只是请求数据时使用GET方法更为有意义(从语义上来说),而在发送需要储存在服务器端的数据时则相反使用POST。

 

17 后加载组件 (Post-load Components)

tag:content

 

你可以仔细端详下你的页面然后自问:“什么是在页面初始化时必须的?”那么其余的内容和组件可以放在后面。

JavaScript是理想的用来分割onload事件之前和之后的选择。例如你有执行拖放、下拉和动画的JavaScript代码和菜单,它们可以稍后加载,因为用户在初始呈现之后才会在页面上拖动元素。其他的可以被后加载的地方包括隐藏的内容(当用户做某项操作才会展现的内容)和被折叠的图片。

可以帮助你的工具有: YUI Image Loader能帮助你延缓加载折叠的图片,而且YUI Get utility 能够很简单的包装运行中的JS和CSS。比如,打开Firebug的网络选项卡去查看Yahoo! Home Page。

当性能指标和其它网站开发的好的实践一致时是不错的。渐进增强的观念告诉我们当支持JavaScript时,会提高用户体验,但你必须确保在没有JavaScript时页面也能工作。所以当你确保页面工作正常时,你会通过延后加载的那些更花哨的脚本比如拖放和动画,来增强你的页面。

 

 

转自:http://www.cnblogs.com/smjack/archive/2008/08/23/1274846.html

你可能感兴趣的:(JavaScript,应用服务器,浏览器,css,脚本)