优化网站速度的几种方式

来源:互联网 发布:龙门县网络问政 编辑:程序博客网 时间:2024/03/29 09:18

在业界有篇很经典的文章,来源于yahoo的开发者社区,它讲述的是如果优化自己的网站的速度,包括从服务器端到客户端。这篇文章影响了很多人,原文可以参照这里:Best Practices for Speeding Up Your Web Site

而本文只是用一种比较通俗的语言来阐述那几种方式,以及如何来优化自己的博客或网站。

 

1:减少自己网站的http请求次数

在现在的网站已经不是简单的文字,这其中还包括更多更为丰富的元素。这样理所当然的增加了服务端与客户端之间的请求数,现在要做的就是尽可能的减少这些响应时间,这是网站优化的第一步,在原文提到:Tenni Theurer在他的博客中所说,HTTP请求在无缓存情况下占去了40%到60%的响应时间,如何优化呢?

合并文件(Combined files)。比如在你的网站很多不同的css文件或script文件,我们尽可能把它们合并到一个文件,合并css一般不会出现什么错误,合并script就要注意了。

图片拼合技术(CSS Sprites)。这个在我早些文章有提到,在这里你可以了解到详情。

图片地图(Image maps)。比如我们要做一个比较华丽的导航栏,这其中也包括每个栏目的字体,然后通过map和area元素来确定坐标来进行事件处理,这样就不想切图后很有小图片那样。确定图片的坐标可能会比较繁琐且容易出错,不具有可读性,所以尽量还是不要实用这个。

尽量少使用内联图像(Inline images)。即一般我们在(X)THML会使用img的src来插入图片。这样做不太好,尽量把它放在样式表(stylesheets)里面写。

2:使用CDN(Content Delivery Network)内容分布网络

这个可能退普通的个人用户来说有些可望不可即了。因为现在的每个地域的网络状态都不一样,比如网站的服务器在成都,那么每个地区的访问的速度都会不同,而CDN的作用在于由一系列分散到各个不同地理位置上的Web服务器组成的,它提高了网站内容的传输速度。用于向用户传输内容的服务器主要是根据和用户在网络上的靠近程度来指定的。目前国内这种服务都比较贵,而且听说对动态网站效果不是太好,我没用过无从考证。不过向是新浪,搜狐,腾讯这些大型门户网站都用到这种服务。

3:在http头部加一个Expires或Cache-Control

浏览器(和代理)使用缓存来减少HTTP请求的大小和次数以加快页面访问速度。Web服务器在HTTP响应中使用Expires文件头来告诉客户端内容需要缓存多长时间。下面这个例子是一个较长时间的Expires文件头,它告诉浏览器这个响应直到2010年4月15日才过期。
Expires: Thu, 15 Apr 2010 20:00:00 GMT
如果你使用的是Apache服务器,可以使用ExpiresDefault来设定相对当前日期的过期时间。下面这个例子是使用ExpiresDefault来设定请求时间后10年过期的文件头:
ExpiresDefault “access plus 10 years”
要切记,如果使用了Expires文件头,当页面内容改变时就必须改变内容的文件名。依Yahoo!来说我们经常使用这样的步骤:在内容的文件名中加上版本号,如yahoo_2.0.6.js。

这个是需要在服务器端进行设置。

4:使用Gzip压缩文件内容。

这个也是需要服务器端支持的。说一下Gzip:

Gzip是目前最流行也是最有效的压缩方式。这是由GNU项目开发并通过RFC 1952来标准化的。另外仅有的一个压缩格式是deflate,但是它的使用范围有限效果也稍稍逊色。
Gzip大概可以减少70%的响应规模。目前大约有90%通过浏览器传输的互联网交换支持gzip格式。如果你使用的是Apache,gzip模块配置和你的版本有关:Apache 1.3使用mod_zip,而Apache 2.x使用moflate。

这里有个网站可以检查你的网站是不否启用了Gzip,而且也可以看到压缩率等信息,如果没有你可以自自己通过搜索,开启相应环境下的Gzip。

5:把样式表放到头部

在研究Yahoo!的性能表现时,我们发现把样式表放到文档的<head />内部似乎会加快页面的下载速度。这是因为把样式表放到<head />内会使页面有步骤的加载显示。简单的说你css文件放到<head/>之前。

6:尽量把Scripts放到底部

这点我个人感觉很实用而且很有效,特效在现在的注重于用户交互的网站,其中的javascript好几个加起了也至少有好几十K。浏览器的解析顺序是由上到下,而网站的主要的就是内容,把Scripts放到底部能够保证访客最先看到的是内容。这里有个我优化的例子:用css的position属性控制div顺序。不过有时候把所有的Scripts放到底部可能会导致部分功能失效,这点要特别注意,及时进行调试。

7:避免使用CSS表达式(Expression)

CSS表达式是动态设置CSS属性的强大(但危险)方法。Internet Explorer从第5个版本开始支持CSS表达式。下面的例子中,使用CSS表达式可以实现隔一个小时切换一次背景颜色:
background-color: expression( (new Date()).getHours()%2 ? “#B8D4FF” : “#F08A00″ );
如上所示,expression中使用了JavaScript表达式。CSS属性根据JavaScript表达式的计算结果来设置。expression 方法在其它浏览器中不起作用,因此在跨浏览器的设计中单独针对Internet Explorer设置时会比较有用。
表达式的问题就在于它的计算频率要比我们想象的多。不仅仅是在页面显示和缩放时,就是在页面滚动、乃至移动鼠标时都会要重新计算一次。给CSS表达式增加一个计数器可以跟踪表达式的计算频率。在页面中随便移动鼠标都可以轻松达到10000次以上的计算量。

8:把JavaScript和CSS放到外部

这点也好容易理解。在实际应用中使用外部文件可以提高页面速度,因为JavaScript和CSS文件都能在浏览器中产生缓存。在浏览不同页面,但是都用同一CSS或JavaScript是就不必反复下载。

内置在HTML文档中的JavaScript和CSS则会在每次请求中随HTML文档重新下载。这虽然减少了HTTP请求的次数,却增加了HTML文档的大小。从另一方面来说,如果外部文件中的JavaScript和CSS被浏览器缓存,在没有增加HTTP请求次数的同时可以减少HTML文档的大小。

9:减少DNS的查找次数

这个怎么理解呢?什么是DNS呢?DNS(Domain Name System)中文可以叫域名系统,它提供的是从主机名到IP地址转换的一段计算机程序,在很早以后人们是通过特定的IP来访问某个网站,但是这样很难记,而DNS就是用一些比较好记的词组作为域名,当访客输入域名DNS就把它转化为相应的ip地址。一般情况下返回给定域名对应的IP地址会花费20到120毫秒的时间。而且在这个过程中浏览器什么都不会做直到DNS查找完毕。引用原文的翻译:

缓存DNS查找可以改善页面性能。这种缓存需要一个特定的缓存服务器,这种服务器一般属于用户的ISP提供商或者本地局域网控制,但是它同样会在用户使用的计算机上产生缓存。DNS信息会保留在操作系统的DNS缓存中(微软Windows系统中DNS Client Service)。大多数浏览器有独立于操作系统以外的自己的缓存。由于浏览器有自己的缓存记录,因此在一次请求中它不会受到操作系统的影响。
Internet Explorer默认情况下对DNS查找记录的缓存时间为30分钟,它在注册表中的键值为DnsCacheTimeout。Firefox对DNS的查找记录缓存时间为1分钟,它在配置文件中的选项为network.dnsCacheExpiration(Fasterfox把这个选项改为了1小时)。
当客户端中的DNS缓存都为空时(浏览器和操作系统都为空),DNS查找的次数和页面中主机名的数量相同。这其中包括页面中URL、图片、脚本文件、样式表、Flash对象等包含的主机名。减少主机名的数量可以减少DNS查找次数。
减少主机名的数量还可以减少页面中并行下载的数量。减少DNS查找次数可以节省响应时间,但是减少并行下载却会增加响应时间。我的指导原则是把这些页面中的内容分割成至少两部分但不超过四部分。这种结果就是在减少DNS查找次数和保持较高程度并行下载两者之间的权衡了。

10:压缩和削减JavaScript和CSS

精简是指从去除代码不必要的字符减少文件大小从而节省下载时间。消减代码时,所有的注释、不需要的空白字符(空格、换行、tab缩进)等都要去掉。在 JavaScript中,由于需要下载的文件体积变小了从而节省了响应时间。精简JavaScript中目前用到的最广泛的两个工具是JSMinYUI Compressor。YUI Compressor还可用于精简CSS。
混淆是另外一种可用于源代码优化的方法。这种方法要比精简复杂一些并且在混淆的过程更易产生问题。在对美国前10大网站的调查中发现,精简也可以缩小原来代码体积的21%,而混淆可以达到25%。尽管混淆法可以更好地缩减代码,但是对于JavaScript来说精简的风险更小。
除消减外部的脚本和样式表文件外,<script>和<style>代码块也可以并且应该进行消减。即使你用Gzip压缩过脚本和样式表,精简这些文件仍然可以节省5%以上的空间。由于JavaScript和CSS的功能和体积的增加,消减代码将会获得益处。

11:避免使用跳转

使用跳转会降低用户体验,而且在用户和HTML中增加一个跳转,会拖延页面中的所有元素的现实。

有一种经常被网页开发者忽略却往往十分浪费响应时间的跳转现象。这种现象发生在当URL本该有斜杠(/)却被忽略掉时。例如,当我们要访问http://astrology.yahoo.com/astrology 时,实际上返回的是一个包含301代码的跳转,它指向的是http://astrology.yahoo.com/astrology/  (注意末尾的斜杠)。在Apache服务器中可以使用Alias 或者 mod_rewrite或者the DirectorySlash来避免。

12:去掉重复的Scripts

重复引用脚本的情况在Internet Explorer中会产生不必要的HTTP请求,而在Firefox却不会。在Internet Explorer中,如果一个脚本被引用两次而且它又不可缓存,它就会在页面加载过程中产生两次HTTP请求。即时脚本可以缓存,当用户重载页面时也会产生额外的HTTP请求。

一个避免偶尔发生的两次引用同一脚本的方法是在模板中使用脚本管理模块引用脚本。在HTML页面中使用<script />标签引用脚本的最常见方法就是:
<script type=”text/javascript” src=”menu_1.0.17.js”></script>
在PHP中可以通过创建名为insertScript的方法来替代:
<?php insertScript(”menu.js”) ?>
为了防止多次重复引用脚本,这个方法中还应该使用其它机制来处理脚本,如检查所属目录和为脚本文件名中增加版本号以用于Expire文件头等。

特别提醒下喜欢玩各种插件的wordpress朋友。很多时候我都发现同样是一个Jquery框架在一个页面就被多次加载。注意检查页面代码。

13:配置ETag

这个同样是需要在服务器端进行操作

Entity tags(ETags)(实体标签)是web服务器和浏览器用于判断浏览器缓存中的内容和服务器中的原始内容是否匹配的一种机制(“实体”就是所说的“内容”,包括图片、脚本、样式表等)。

ETag的问题在于,它是根据可以辨别网站所在的服务器的具有唯一性的属性来生成的。当浏览器从一台服务器上获得页面内容后到另外一台服务器上进行验证时 ETag就会不匹配,这种情况对于使用服务器组和处理请求的网站来说是非常常见的。默认情况下,Apache和IIS都会把数据嵌入ETag中,这会显著减少多服务器间的文件验证冲突。
Apache 1.3和2.x中的ETag格式为inode-size-timestamp。即使某个文件在不同的服务器上会处于相同的目录下,文件大小、权限、时间戳等都完全相同,但是在不同服务器上他们的内码也是不同的。
IIS 5.0和IIS 6.0处理ETag的机制相似。IIS中的ETag格式为Filetimestamp:ChangeNumber。用ChangeNumber来跟踪 IIS配置的改变。网站所用的不同IIS服务器间ChangeNumber也不相同。不同的服务器上的Apache和IIS即使对于完全相同的内容产生的ETag在也不相同,用户并不会接收到一个小而快的304响应;相反他们会接收一个正常的200响应并下载全部内容。如果你的网站只放在一台服务器上,就不会存在这个问题。但是如果你的网站是架设在多个服务器上,并且使用Apache和 IIS产生默认的ETag配置,你的用户获得页面就会相对慢一点,服务器会传输更多的内容,占用更多的带宽,代理也不会有效地缓存你的网站内容。即使你的内容拥有Expires文件头,无论用户什么时候点击“刷新”或者“重载”按钮都会发送相应的GET请求。
如果你没有使用ETag提供的灵活的验证模式,那么干脆把所有的ETag都去掉会更好。Last-Modified文件头验证是基于内容的时间戳的。去掉ETag文件头会减少响应和下次请求中文件的大小。微软的这篇支持文稿讲述了如何去掉ETag。在Apache中,只需要在配置文件中简单添加下面一行代码就可以了:
FileETag none

14:让AJAX能够缓存

Ajax经常被提及的一个好处就是由于其从后台服务器传输信息的异步性而为用户带来的反馈的即时性。但是,使用Ajax并不能保证用户不会在等待异步的 JavaScript和XML响应上花费时间。在很多应用中,用户是否需要等待响应取决于Ajax如何来使用。例如,在一个基于Web的Email客户端中,用户必须等待Ajax返回符合他们条件的邮件查询结果。记住一点,“异步”并不异味着“即时”,这很重要。

为了提高性能,优化Ajax响应是很重要的。提高Ajxa性能的措施中最重要的方法就是使响应具有可缓存性,具体的讨论可以查看Add an Expires or a Cache-Control Header。其它的几条规则也同样适用于Ajax:
Gizp压缩文件, 减少DNS查找次数,  精简JavaScript, 避免跳转,  配置ETags

让我们来看一个例子:一个Web2.0的Email客户端会使用Ajax来自动完成对用户地址薄的下载。如果用户在上次使用过Email web应用程序后没有对地址薄作任何的修改,而且Ajax响应通过Expire或者Cacke-Control头来实现缓存,那么就可以直接从上一次的缓存中读取地址薄了。必须告知浏览器是使用缓存中的地址薄还是发送一个新的请求。这可以通过为读取地址薄的Ajax URL增加一个含有上次编辑时间的时间戳来实现,例如,&t=11900241612等。如果地址薄在上次下载后没有被编辑过,时间戳就不变,则从浏览器的缓存中加载从而减少了一次HTTP请求过程。如果用户修改过地址薄,时间戳就会用来确定新的URL和缓存响应并不匹配,浏览器就会重要请求更新地址薄。
即使你的Ajxa响应是动态生成的,哪怕它只适用于一个用户,那么它也应该被缓存起来。这样做可以使你的Web2.0应用程序更加快捷。

15、尽早刷新输出缓冲

当用户请求一个页面时,无论如何都会花费200到500毫秒用于后台组织HTML文件。在这期间,浏览器会一直空闲等待数据返回。在PHP中,你可以使用 flush()方法,它允许你把已经编译的好的部分HTML响应文件先发送给浏览器,这时浏览器就会可以下载文件中的内容(脚本等)而后台同时处理剩余的 HTML页面。这样做的效果会在后台烦恼或者前台较空闲时更加明显。
输出缓冲应用最好的一个地方就是紧跟在<head />之后,因为HTML的头部分容易生成而且头部往往包含CSS和JavaScript文件,这样浏览器就可以在后台编译剩余HTML的同时并行下载它们。 例子:
… <!– css, js –>
</head>
<?php flush(); ?>
<body>
… <!– content –>
为了证明使用这项技术的好处,Yahoo!搜索率先研究并完成了用户测试。

16、使用GET来完成AJAX请求

Yahoo!Mail团队发现,当使用XMLHttpRequest时,浏览器中的POST方法是一个“两步走”的过程:首先发送文件头,然后才发送数据。因此使用GET最为恰当,因为它只需发送一个TCP包(除非你有很多cookie)。IE中URL的最大长度为2K,因此如果你要发送一个超过2K的数据时就不能使用GET了。
一个有趣的不同就是POST并不像GET那样实际发送数据。根据HTTP规范,GET意味着“获取”数据,因此当你仅仅获取数据时使用GET更加有意义(从语意上讲也是如此),相反,发送并在服务端保存数据时使用POST。

17. 延迟载入组件 (Post-load Components)和18. 预载入组件 (Preload Components)

简单的说就有些你不必要的东西可以稍后在加载它们,而欲载入说的说的是

预先利用在浏览器空档时,载入一些使用者接下来可能会用到的文件等

19:减少DOM元素数量(Reduce the Number of DOM Elements)

一个复杂的页面意味着需要下载更多数据,同时也意味着JavaScript遍历DOM的效率越慢。比如当你增加一个事件句柄时在500和5000个DOM元素中循环效果肯定是不一样的。
大量的DOM元素的存在意味着页面中有可以不用移除内容只需要替换元素标签就可以精简的部分。你在页面布局中使用表格了吗?你有没有仅仅为了布局而引入更多的<div>元素呢?也许会存在一个适合或者在语意是更贴切的标签可以供你使用。

20:将元件放到不同的域名目录

原因是这样的,在同一个域名在同一时间只能接受两个请求并进行,如果用不同域名就可以实现平行下载。比如我可以用img.g9net.com这个链接来存放图片并进行链接。比如腾讯QQ,域名是www.QQ.com。而它用来存放的图片域名地址大致为img1.qq.com,而不是类似www.qq.com/img 这样的目录。

21:减少Iframe的数量

ifrmae元素可以在父文档中插入一个新的HTML文档。了解iframe的工作理然后才能更加有效地使用它,这一点很重要。
<iframe>优点:解决加载缓慢的第三方内容如图标和广告等的加载问题 ;Security sandbox ;并行加载脚本

<iframe>的缺点:即时内容为空,加载也需要时间 ;会阻止页面加载 ;没有语意

22:不要有404错误页面

这个也好理解除了会破坏使用者体验外,还会停止平行下载,此外,有些浏览器还会花时间去解析传回来的404文件。

23:减小Cookie体积

HTTP coockie可以用于权限验证和个性化身份等多种用途。coockie内的有关信息是通过HTTP文件头来在web服务器和浏览器之间进行交流的。因此保持coockie尽可能的小以减少用户的响应时间十分重要。具体可以这样做:

  • 去除不必要的coockie 。
  1. 使coockie体积尽量小以减少对用户响应的影响 。
  2. 注意在适应级别的域名上设置coockie以便使子域名不受影响 。
  3. 设置合理的过期时间。较早地Expire时间和不要过早去清除coockie,都会改善用户的响应时间。
  4. 24:对于页面内容使用无coockie域名

    当浏览器在请求中同时请求一张静态的图片和发送coockie时,服务器对于这些coockie不会做任何地使用。因此他们只是因为某些负面因素而创建的网络传输。所有你应该确定对于静态内容的请求是无coockie的请求。创建一个子域名并用他来存放所有静态内容。
    如果你的域名是www.example.org,你可以在static.example.org上存在静态内容。但是,如果你不是在 www.example.org上而是在顶级域名example.org设置了coockie,那么所有对于static.example.org的请求都包含coockie。在这种情况下,你可以再重新购买一个新的域名来存在静态内容,并且要保持这个域名是无coockie的。Yahoo!使用的是 ymig.com,YouTube使用的是ytimg.com,Amazon使用的是images-anazon.com等等。
    使用无coockie域名存在静态内容的另外一个好处就是一些代理(服务器)可能会拒绝对coockie的内容请求进行缓存。一个相关的建议就是,如果你想确定应该使用example.org还是www.example.org作为你的一主页,你要考虑到coockie带来的影响。忽略掉www会使你除了把coockie设置到*.example.org外没有其它选择,因此出于性能方面的考虑最好是使用带有www的子域名并且在它上面设置coockie。

25:减少DOM访问
使用JavaScript访问DOM元素比较慢,因此为了获得更多的应该页面,应该做到:

  • 缓存已经访问过的有关元素 。
  • 线下更新完节点之后再将它们添加到文档树中 。
  • 避免使用JavaScript来修改页面布局 。

有关此方面的更多信息请查看Julien Lecomte在YUI专题中的文章“高性能Ajax应该程序”

26、开发智能事件处理程序

有时候我们会感觉到页面反应迟钝,这是因为DOM树元素中附加了过多的事件句柄并且些事件句病被频繁地触发。这就是为什么说使用event delegation(事件代理)是一种好方法了。如果你在一个div中有10个按钮,你只需要在div上附加一次事件句柄就可以了,而不用去为每一个按钮增加一个句柄。事件冒泡时你可以捕捉到事件并判断出是哪个事件发出的。
你同样也不用为了操作DOM树而等待onload事件的发生。你需要做的就是等待树结构中你要访问的元素出现。你也不用等待所有图像都加载完毕。
你可能会希望用DOMContentLoaded事件来代替onload,但是在所有浏览器都支持它之前你可使用YUI 事件应用程序中的onAvailable方法。

27:使用<link>代替@import

前面的最佳实现中提到CSS应该放置在顶端以利于有序加载呈现。 在IE中,用@import把<link>当到底部的作用是一样的,因此最好不要使用它。

28:避免使用滤镜

IE独有属性AlphaImageLoader用于修正7.0以下版本中显示PNG图片的半透明效果。这个滤镜的问题在于浏览器加载图片时它会终止内容的呈现并且冻结浏览器。在每一个元素(不仅仅是图片)它都会运算一次,增加了内存开支,因此它的问题是多方面的。
完全避免使用AlphaImageLoader的最好方法就是使用PNG8格式来代替,这种格式能在IE中很好地工作。如果你确实需要使用 AlphaImageLoader,请使用下划线_filter又使之对IE7以上版本的用户无效。

29:优化图像

这个简单的说设计好后图片不要急于直接用,最好用图片压缩工具压缩。我本人很喜欢png这种格式,所用的工具为PNGOUTWin,效果相当不错。

30:优化CSS Spirite

  • 1:在Spirite中水平排列你的图片,垂直排列会稍稍增加文件大小;
  • 2:Spirite中把颜色较近的组合在一起可以降低颜色数,理想状况是低于256色以便适用PNG8格式;
  • 3:便于移动,不要在Spirite的图像中间留有较大空隙。这虽然不大会增加文件大小但对于用户代理来说它需要更少的内存来把图片解压为像素地图。100×100的图片为1万像素,而1000×1000就是100万像素。

31:不要在HTML中缩放图像

不要为了在HTML中设置长宽而使用比实际需要大的图片。如果你需要:
<img width=”100″ height=”100″ src=”mycat.jpg” alt=”My Cat” />
那么你的图片(mycat.jpg)就应该是100×100像素而不是把一个500×500像素的图片缩小使用。

32:favicon.ico要小且可缓存

favicon.ico是位于服务器根目录下的一个图片文件,也就是在浏览器旁边的那个网站小图标。它是必定存在的,因为即使你不关心它是否有用,浏览器也会对它发出请求,因此最好不要返回一个404 Not Found的响应。由于是在同一台服务器上,它每被请求一次coockie就会被发送一次。这个图片文件还会影响下载顺序,例如在IE中当你在 onload中请求额外的文件时,favicon会在这些额外内容被加载前下载。为了减少favicon.ico带来的弊端,要做到

1:文件尽量地小,最好小于1K

2:在适当的时候(也就是你不要打算再换favicon.ico的时候,因为更换新文件时不能对它进行重命名)为它设置Expires文件头。你可以很安全地把Expires文件头设置为未来的几个月。你可以通过核对当前favicon.ico的上次编辑时间来作出判断。

Imagemagick可以帮你创建小巧的favicon。

33:保持单个内容小于25K

这条限制主要是因为iPhone不能缓存大于25K的文件。注意这里指的是解压缩后的大小。由于单纯gizp压缩可能达不要求,因此精简文件就显得十分重要。

34:打包组成复合文本

这条限制主要是因为iPhone不能缓存大于25K的文件。注意这里指的是解压缩后的大小。由于单纯gizp压缩可能达不要求,因此精简文件就显得十分重要。

总结一下:

对于普通的前端工作者,最重要的就是关心CSS和Javascript等,比较好下手

对于CSS:把样式表置于顶部:避免使用CSS表达式(Expression);使用外部JavaScript和CSS;削减JavaScript和CSS;削减JavaScript和CSS

对于Javascript:把脚本置于页面底部;使用外部JavaScript和CSS;削减JavaScript和CSS;剔除重复脚本;减少DOM访问

 

 

 

原文链接http://www.g9net.com/2009/04/05/optimize-the-speed-of-the-web-in-several-ways.html