您的位置:首页 > 运维架构 > 网站架构

35条网站性能优化规则 学习笔记

2013-06-25 00:11 381 查看

最近看了YSlow给出的35条网站性能优化建议,感觉很受益,但是阅读地同时也产生了很多的疑惑,因为其中很多建议都只是笼统地提了一句,关于为什么要那么做或者如何做并没有给出详细说明,针对此,我做了一些研究,贴在这里,希望给像我一样刚入门的朋友一点启发。不过目前研究的还比较浅,有点内容还没有深刻理解,我会不断学习,不断实践,不断更新。

之前我把每条建议的英文原文贴上,然后再在每条建议的后面贴上我自己的理解,现在感觉这种做法不是很好,所以今天更新,只写我自己的理解,对原文有兴趣的朋友请访问http://yslow.org/查看。

1.最小化HTTP请求数

在服务器,数据库等性能完全跟得上的情况下,终端用户访问时间基本取决于前端,用户总访问时间的80%都浪费在了前端上,用来下载页面上的各个组件(例如图像,样式表,js脚本,flash等)及页面的解析和渲染。常用的可以减少http的请求次数的方法有以下4种:

1).合并文件:将多个css文件合成一个,同理多个js合成一个;

2).使用css sprite技术:将多张小图拼成一张大图,然后通过background-position来定位;

3).图片地图:这个不推荐,我也不介绍了。

4).内联图片:即将图片转换成对应的base64编码直接写在程序中,这样可以避免http请求,但这样的做法会增加html文件的长度,并且无法 利用cache,所以一个折衷的办法就是把图像的代码写在css文件中,这样既可以减少http请求数,又可以应用缓存了。这里给大家推荐一个将图片转成 编码的网站:http://imagetobase64.com/
 

2.使用CDN网络



CDN原理图
           CDN即Content Delivery Network,内容分发网络,该网络在全球有N多个节点,每个节点上都有完整的数据(目前基本应用在静态数据上,如css,images,js等,动态的好像也可以,但我不明白是怎么做的),它可以根据终端用户的地理位置、运营商等动态选择就近的节点以响应用户的请求,从而加快用户的访问速度。

但CDN是一个昂贵的系统,一般只有大型企业才支付得起,例如新浪、网易等公司均采用了CDN加速技术。(应该是指这些公司都有一套自己独立的CDN系统)

对于中小企业,可以采用CDN提供商提供的CDN网络,如Webluker,盛大云加速乐等,大家可以点击链接了解下。(关于CDN更多请参阅http://baike.baidu.com/view/8689800.htm?fromId=21895&redirected=seachword


3.避免图片的src指空

  空的src地址,如<img src="${url}">,<script src="">以及<link href="">等,会被浏览器认为是一个相对路径,即当前页面地址+“”,即当前页面地址,浏览器会试图从这个地址(IE下是页面所在的目录,如www.example.com/dir/a.html会请求www.example.com/dir/)获取数据以填充img或下载 js,css等资源,而实际上这个错误的地址是不会返回我们想要的信息的,并且导致服务器重新计算了一遍页面,白白消耗了server端的带宽和cpu。 尤其在一个千万级访问量甚至更高的WEB站点里,这样会导致你的服务器和带宽的成本显著增加。

另外一个隐患是,重新请求某个页面可能会导致用户的一些信息被无意中修改,例如session,cookies,或者ajax操作。关于空src引起的问题请参考http://blog.csdn.net/axman/article/details/6360707

推荐阅读"Empty image src can destroy your site"

4.添加Expires或Cache-Control头

使用expires或cache-control头来缓存静态文件,减少后续访问的请求次数。这里要说明一点,html文档的缓存是通过在head标签中的meta标签设置的,但js和css,images文件却没办法这样做,它们的缓存时间是在服务器端设置的。

expires用法:

· expires用于网页缓存过期时间

· expires出现在http-equiv属性中,使用content属性表示页面缓存的过期时间

· expires用于设定网页的过期时间,一旦过期就必须从服务器上重新加载.时间必须使用GMT格式.

示例:<meta http-equiv="expires" content="Sunday 26 October 2008 01:00 GMT" />

Cache-Control:

概念:用于控制HTTP缓存(在HTTP/1.0中可能部分没实现,仅仅实现了Pragma: no-cache,HTTP/1.1中全部实现) ,常见的取值有private、no-cache、max-age、must-revalidate等,默认为private。其作用根据不同的重新浏览方式分为以下几种情况:
(1) 打开新窗口
如果指定cache-control的值为private、no-cache、must-revalidate,那么打开新窗口访问时都会重新访问服务器。而如果指定了max-age值,那么在此值内的时间里就不会重新访问服务器,例如:
Cache-control: max-age=5,表示当访问此网页后的5秒内再次访问不会去服务器
(2) 在地址栏回车
如果值为private或must-revalidate(和网上说的不一样),则只有第一次访问时会访问服务器,以后就不再访问。如果值为no-cache,那么每次都会访问。如果值为max-age,则在过期之前不会重复访问。
(3) 按后退按扭
如果值为private、must-revalidate、max-age,则不会重访问,而如果为no-cache,则每次都重复访问
(4) 按刷新按扭
无论为何值,都会重复访问 



参考自:http://www.blogjava.net/dashi99/archive/2008/12/30/249207.html

示例代码:

<meta http-equiv="Cache-Control" content="max-age=7200" />  

<meta http-equiv="Cache-Control" content="pragma=no-cache" />  

5. 配置ETag

ETag是服务器返回的一个资源标识ID,是一个唯一的序列,在浏览器第二次及以后请求该资源时会通过此标识校验资源有无改动,若无,则返回一个304状态码,告诉浏览器应用缓存中的资源。

ETag的问题就是在多服务器集群的时候,有些 webserver 的 Etag 的计算方法中包含了 inode,另外有些网站同时使用了IIS和Apche,这两个服务器返回的ETag格式也不相同,这就使得各个服务器返回的ETag不相同,从而导致了 冗余的HTTP请求,针对这种情况的解决方法就是:改变webserver对etag的计算方法,使它们返回相同格式的ETag就可以了。

网上有些人认为ETag对静态资源的用处不大,不如用last-modified来得简单,ETag应用在动态资源上还可以。我个人也这样认为。

如果同时使用了ETag和last-modified,则服务器会同时检查这两个标识,只有当这两个标识都没有改动时才可以返回304.

补充:

Expires、Cache-Control、Last-Modified 及 ETag 的关系 

Cache 机制可能是HTTP 1.1协议中最复杂的一个组成部分,它的目的有两个:一是降低网络上发送HTTP请求的次数,这采用"过期"机制(Expiration Mechanism);二是降低网络上完整回复HTTP请求包的次数,这采用"验证"机制(Validation Mechanism)。

"过期"机制

     HTTP Cache机制的最理想目标是使客户端根本不发起非必要的请求。它的基本原理是为每个被请求实体(Entity)设定一个内容将变更的时间点,从该实体第 一次被请求后到这个时间点到达之前实体的内容是不变的,因而可以直接使用Cache中缓存的内容满足针对该实体的后续请求,而不必每次由源HTTP服务器 做响应。

HTTP服务器通过两种实体头(Entity-Header)来实现"过期"机制:Expires头和Cache-Control头的max-age子项。

"验证"机制

     HTTP服务器为每个作为响应发送的实体附加一个"验证子",当Cache中的响应"过期"后,Cache将该验证子发送给HTTP源服务器以验证是否该响应已确实过期. 如果确认过期则源服务器发送新响应包,否则只发送改变的实体头,这种机制可有效节省带宽.

     HTTP服务器通过两种方式实现该"验证子":ETag以及Last-Modified Date.验证子的特点在于它会随着所代表实体的变化而变化,就像是实体的指纹,而且验证子可分为强验证子和弱验证子两种,强验证子会严格随实体变化而变 化,弱验证子则只是在实体发生显著变化时才变化.

一、Max-age和expire 

 

Max-age和expire均作用于浏览器端,都可以定义缓存过期时间,但是二者还是存在较大差别:

 

1.Expires在HTTP/1.0中已经定义,Cache-Control:max-age在HTTP/1.1中才有定义,为了向下兼容,仅使用max-age不够。

 

2.max-age 指定的是从文档被访问后的存活时间,这个时间是个相对值,相对的是文档第一次被请求时服务器记录的请求时间(Atime)。

 

3.Expires指定的时间可以是相对文件的最后访问时间(Atime)或者修改时间(MTime)

 

4.max- age可以使用header设置,如果没有使用header设置,则根据expires计算得出,此时max-age和expires相同或者不不同。如 果是相对文件的最后访问时间(注:604800s=7days),很明显max-age和expires相同。

 

如果是绝对修改时间,则二者不同。

 

5.Cache- Control的max-age优先级高于Expires(至少对于Apache是这样的),这意味着如果max-age和expires中的数字不一样 时,采取max-age值。如果使用了header定义了Cache-Control: max-age,则完全不需要加上Expries,因为根本没用。例如:你在浏览A页面时,A页面加载了一个名为B的JS文件,该JS文件的 Response Header中有Cache-Control: max-age=600,如果你再访问任何其他用到B文件的页面时,600秒内浏览器完全不会向服务器发送请求,直接使用Cache中的内容。600秒以 后,Cache失效。想每一次都发送请求,则max-age设为负数。

 

二、Etag和Last-Modified 

ast-Modified: Date, If-Modified-Since: Date 和ETag作用于服务器端,继续刚才上面的例子,当max-age超过以后,浏览器会向服务器端发送请求。在B文件上一次的Response Header中会带有Last-Modified: Date,这时新请求的Header中会有If-Modified-Since: Date。服务器端在收到请求后,将B的最后修改日期和Header中的日期进行对比,如果相同则说明B没有被修改过,返回304 Not Modified,否则返回200和B的内容。

 

Etag和Last-Modified也是类似的,只不过检查的不是最后修改的时间,而是被请求内容的Hash ,Etag和Last-Modified在Apache中默认都是打开的,关闭的方法是 :

Header unset Etag 

Header unset Last-Modified 

 

让 我们回过头来比较一下Expires和Last-Modified这两个东西,似乎Last-Modified比不上Expires,因为虽然它能够节省 一点带宽,但是还是逃不掉发一个HTTP请求出去,而Expires却使得浏览器干脆连HTTP请求都不用发,岂不痛快!那还要Last- Modified这个物体干什么?理想状况的确是这样,不过当用户在IE或者Firefox里面按F5或者点击Refresh按钮的时候(不是在URL栏 里重新输入一遍URL然后回车),就算对于有Expires的URI,一样也会发一个HTTP请求出去,所以,Last-Modified还是要用的,而 且要和Expires一起用。

---------------------------------------------------------------------

Last-Modified和Expires

Last- Modified标识能够节省一点带宽,但是还是逃不掉发一个HTTP请求出去,而且要和Expires一起用。而Expires标识却使得浏览器干脆连 HTTP请求都不用发,比如当用户F5或者点击Refresh按钮的时候就算对于有Expires的URI,一样也会发一个HTTP请求出去,所 以,Last-Modified还是要用的,而 且要和Expires一起用。

Etag和Expires

如 果服务器端同时设置了Etag和Expires 时,Etag原理同样,即与Last-Modified/Etag对应的HttpRequest Header:If-Modified-Since和If-None-Match。我们可以看到这两个Header的值和WebServer发出的 Last-Modified,Etag值完全一样;在完全匹配If-Modified-Since和If-None-Match即检查完修改时间和 Etag之后,服务器才能返回304.

Last-Modified和Etag

Last-Modified 和ETags请求的http报头一起使用,服务器首先产生 Last-Modified/Etag标记,服务器可在稍后使用它来判断页面是否已经被修改,来决定文件是否继续缓存

原文出处:http://hi.baidu.com/fengyun409/item/7b7d381a9c28000ce65c36ee

6.Gzip Components 压缩内容

在传输前对你的内容进行压缩,以减少内容的大小从而缩短响应时间。对HTML,js,css,xml,json等所有文本内容都要压缩,并且不止是外联的css,js等文件要压缩,内联的也应该被压缩,而这点是经常被我们忽略的。

压缩常用的格式有两种,分别是gzip和deflate,其中gzip比deflate更常用。

关于gzip,另外要说明的一点是,用户输入网址发起访问,浏览器将此请求发出,所以请求头是浏览器写的,而浏览器在请求头中默认都会设置:Accept-Encoding : gzip, deflate 来告诉服务器它可以解析gzip或deflate的压缩格式,所以在请求中设置gzip这一步不用我们管(包括js,css的请求头,都会自动带这个,至少我目前发现的是这样,如果不对,请留言告诉我,谢谢)。

虽然浏览器告诉服务器可以接受压缩的内容,但服务器是否会压缩仍取决于服务器的配置,如果服务器启用了压缩,则会传回压缩的内容,浏览器会将得到的内容先解压再解析。但如果服务器没有启用压缩,那就没有压缩和解压的过程。

7.Put Stylesheets at the Top  把样式表放在页面顶部

把css放在head区,放在网页正文之前。因为有的浏览器在没有遇到css时会拒绝解析页面(如果一直到页面底部如遇到</html>标签 时还没有遇到css,则就表示此页面没有css,则不会再等,会开始解析页面。这是我的理解哈,有不对的话请大家留言指正),会造成长时间的页面空白。

相反,如果把css放在head区,则可以渐进地显示页面,即加载一点就显示一点,不过这点我还没理解,前阵子看了How browsers work这篇文章,按照对那篇文章的理解,我觉得应该是先解析dom,后解析样式表,这样的话,这里这条就矛盾了,这个有待我进一步研究,研究明白了再写 博文记录。这里大家就记住把css放在head里就对了。

8.Put Scripts at the Bottom

把js放在页面底部,一般是</body>和</html>之间。浏览器一般可以针对每个域名可以同时下载两个资源,但是如果遇 到了js需要下载的情况,则会阻塞所有其它的下载,哪怕是不同域名的。另外当js下载完成后会立即执行,而这执行期间也会阻塞页面其它资源的下载和dom 的解析。所以推荐将js放在页面渲染完成后再去加载。script标签可以用defer属性标明延迟加载,即,如果一个script标签设置了 defer,则即使这个标签写在head区,也不会立即被下载和执行,而会等页面加载完成后才被加载,但是defer只针对IE有效,而且能设置 defer的js其实都是可以放在底部的,所以我们只要把script标签放在页面底部就ok了,各浏览器都兼容。

9.Avoid CSS Expressions 避免使用CSS表达式

避免使用css experession,因为它执行的次数远比你想像的要多得多,页面上一次不经意的鼠标划动可能就会引起上万次cpu计算,所以如果一定要用,也尽量使 用那种只执行一次的,即一次执行之后会生成一个固定的值,以后 就不再计算了。如果必须要用动态计算的,那么可以采用js来实现 ,而不是css expression.

10.Make JavaScript and CSS External 使用外联的js和css

建议将css和js以外联方式引用以充分利用cache,只有一个例外就是针对首页,首页可以采用内联来减少http请求数,加快页面显示速度,文中说首 页内联的原因是首页被人们访问的次数不会太多,而且样式一般比较特殊,不像其它页面一样有相同的页面模板(因为就有相同的样式部分),所以首页的样式可以 内联。并且应该在首页加载完成之后,再在后台动态加载后续页面的css和js,以提高后续页面的访问速度。

但是首页访问不多这一点我不太苟同,这应该要视网站而定,有此网站用户是经常性会回到首页的,比如说百度搜索。所以究竟内联还是外联,还是要视情况而定吧。。

11.Reduce DNS Lookups 减少DNS查询的时间

用户访问网站的过程如下:

1.在地址栏输入网站地址,如www.example.com;

2.本地DNS得到这个请求,查询本地DNS缓存,如果有这条记录,则直接返回对应的IP;否则,请求网络上的DNS服务器,得到相应的IP,返回给客户机,并缓存这条记录;(这网络请求的过程中具体还有好几步,我以后会研究明白,再来做记录,目前大家可以先看看这篇文章http://www.cnblogs.com/see7di/archive/2011/06/12/2239766.html

3.浏览器向得到的IP发起建立连接请求,得到响应后建立连接,请求数据;

4.Server端计算所需数据,并返回给client端;

5.client端,即浏览器,解析数据并显示在浏览器窗口中,至此,请求完成。

在 一次请求中,DNS解析可以占到请求时间的三分之一左右(这点有待验证),所以如果可以缩短DNS解析时间,就可以加快页面的打开速度。缩短DNS解析的 方法可以通过延长DNS缓存的时间,选用更快的DNS Server,减少域名总数(例如原来有5个img server,分别为img1.xxx.com至img5.xxx.com,则现在可以减少到3个)等等,但是减少域名个数又会降低资源并行下载的数量, 因为同一域名最多可以并行下载两个资源,所以这里需要一个折衷方案,作者的建议就是将资源分布在大于等于2但小于等于4个域名上(这个也有待验证,例如针 对多大的系统选用多少个域名是最合理的等)。

12.Minify JavaScript and CSS  压缩css和js

压缩js和css,很简单,压缩会减小文件的大小,加快下载速度。需要说明的一点就是我们一般会压缩外联的js及css,但是很少考虑内联样式及 js的压缩,作者认为内联的也同样需要压缩,学习了。压缩常用的工具有JSMIn和YUI Compressor,大家可以点击文中的链接了解下。

文中还说了一个Obfuscation,目前我还不了解这东西,不过根据文中的意思应该是一个比JSMin压缩的更彻底的一种工具,但是会有一定的风险,鉴于它压缩的强度并没有大很多且有风险,所以不提倡使用。

13.Avoid Redirects 避免重定向

避免重定向,因为重定向期间页面一直处于空白状态。重定向有几种方式,一种是response告诉客户端向一个新的地址发请求,即通过301或 302状态码,另一种是通过js,第三种是html的refresh标签;文中建议如果一定要用重定向,最好使用第一种,关于这个,我需要再研究一下。

还有一点值得一提,按照文中的意思,一个不以反斜杠结尾的URL地址会导致一次重定向,例如www.a.com/xxx会导致服务器端返回一个301,告诉浏览器重定向到www.a.com/xxx/,因此建议所有的URL都以/结尾.关于这点我在网上简单查了一下,好像确实如此.以后我会自己测试下,然后会把结果更新上来.

一 般使用重定向的情况是:网站迁移或个性化信息引导,比如一个网站搬到新的域名下了,或电子商务网站为不同类型的用户展示不同的信息时.关于网站迁移的情 况,建议使用CNAME结合Alias或mod_rewrite技术来实现; 关于个性化导引,如果代码(重定向前的和重定向后的)在同一服务器上,则可以采用Alias和mod_rewrite来做。

www.a.com CNAME www.b.com

www.b.com a  12.32.2.32

l 关于Alias的简单介绍:

例如www目录下没有 /zen目录,但是由于某种原因需要访问这个目录,那么可以在url连接访问/zen的时候,将该请求指定到系统下的一个其它目录,比如/home/zen/www/,做法如下:

我们需要这么设置
Alias /zen /home/zen/www    

<Directory /home/zen/www>    
Order allow,deny    
Allow from all    
</Directory> 

l 关于mod_rewirte,目前还没有研究,这里有一篇mod_rewirte详解,大家可以先参考,待我研究明白后再跟大家分享心得

14.Remove Duplicate Scripts 去除重复的js脚本

避免重复下载同一个js文件,这个情况发生在团队共同协作的时候,尤其一个页面由多个队员合作完成时。如果一个js被引了两次且不可缓存,则在IE 下会引发两次HTTP请求,但在FF下只会请求一次;如果可以缓存,应该都是一次(这个有待验证,文中说得不是很明白)。文中说即使这个js设置了缓存期 限,但在reload时依然会发HTTP请求,这点我还没理解,需要研究下reload和cache机制的关系。

除了下载的差异,该js在 IE和FF都会被执行两次,执行次数与文件缓存与否没有关系,只有文件引用的次数有关系,而这将降低页面的渲染速度。我们可以使用一个js manager来避免同一个js被多次引用,但现在是否有这样的js manager还需要研究下。当然我认为最简单的就是发布前仔细检查下页面。

15.Make Ajax Cacheable 缓存AJax请求

Ajax请求也是可以被缓存的,这一点我之前倒没有想到过,我想也是不少人会忽略的问题吧。其实Ajax请求除了是异步的,跟其它请求是没有区别的,所以 之前讲过的优化策略Ajax都可以使用。例如压缩响应的内容,压缩js,设置Etag等等,这些操作都是在服务器端做的,所以要求服务器端做相应的配置。 在发送ajax请求前,我们也可以自己设置header,jquery中是通过$.ajax的beforeSend()中设置,具体做法还有待实践。

16.Flush the Buffer Early 早些返回数据

因为服务器端生成html文件需要一定的时间,且一般的做法是在整个文件生成完后才一次性返回,这会造成客户端有一段空白的等待时间,即什么也没做。所以 建议服务器端能够渐进地返回数据,生成一点就返回一点,这样可以加快页面的显示速度,避免用户长时间面对一个空白的页面。例如可以 在</head>标签生成后先将head部分返回,因为head区域一般会包含css,js等外联文件,浏览器可以一边下载这些资源一边等待 后续html标签的到来。

17.Use GET for AJAX Requests 使用Get方式发送ajax请求

常用的ajax请求有两种,即get和post, 而get比post响应时间快,因为它只发一次请求,而post要发两次,第一次发请求头,第二次发请求体,所以建议用get。但是get有容量限制,大 于2K(对get的限制IE是2K,FF应该是4K)的内容只能用post.

除了容量,get方式的另一个缺点就是安全性不高,根据Http规范,get是用来获取数据的,而post是用来提交数据的,所以如果只是获取数据 的话,都应该用get,因为你只是从服务器端取数据,并不会修改服务器内容,所以不存在安全性问题。而如果你是提交数据,比如说用户注册,上传文件等,那 就需要用post方式来保证容量和安全性。

18.Post-load Components 延迟加载不必要的组件

仔细分析下你的页面,问问自己:究竟哪些东西是必须提前加载的?哪些东西是可以放在页面加载之后加载的?这样来将一些不必要的资源延迟加载,以加快页面的显示速度。

19.Preload Components 提前加载组件

提前加载和延迟加载是相对的,但它们的目的相同,都是为了更快的显示页面。提前加载是指在当页面加载完成之后,可以利用用户浏览网页的空闲时间,提前加载后续页面需要用到的组件,以此来加快后续页面的响应速度。有3种情况可以考虑提前加载:

1. 后续页面会用到的组件,例如google主页会在页面加载完成后请求一个sprite图片,这个图片在主页上并没有用到,但它在搜索结果页会被用到;

2.针对用户行为的个性化信息,例如yahoo搜索页,当用户在搜索框输入时会根据用户输入的内容请求一些个性化的组件;

3.网站升级或重构时,在发布新版网站之前,可以先陆续地加载新的组件,使之被用户缓存,这样当网站真正升级后可以加快用户的访问速度。

20.Reduce the Number of DOM Elements 减少dom节点的数量

减少dom节点的个数,因为复杂的dom会增加js访问dom节点的时间,尤其当你要增删一个节点的时候。如果一个页面中节点过多,那就你的网页就应该考虑重新设计了:there must be something wrong.YUI CSS utilities,文中推荐了这个工具,这个待我研究下是干什么的。

21.Split Components Across Domains 将内容分放在多个域名下

将组件分发在2-4个不同的域名上,以使资源可以最大程序地并行下载,例如可以将动态内容放在www.example.com,而将静态内容如图片,css,js等放在static1.example.com和static2.example.com上。

22.Minimize the Number of iframes 尽量少使用iframe

尽量少使用iframe, 只在确实应该使用时才用。iframe的优点是可以并行下载js,提供了安全的水箱机制,可以用来加载第三方的一些比较慢的内容,如广告等;缺点是无语义,不利于seo; 会阻塞页面加载,比较消耗资源。

23.No 404s

http请求是很耗时的,所以要避免一些404的链接,例如一个错误的js文件地址等,这种情况一则会阻塞其它资源的并行下载,二则在响应返回后浏览器试 图去解析这个不存在的文件也会耗时(这点我不明白,一个404的响应浏览器还会去解析“文件”?根本就不存在这所谓的文件,浏览器没那么傻吧)

24.Reduce Cookie Size 减小cookie的大小

减小cookie的大小,因为在发请求时浏览器会将cookie信息发送到server端,所以应该只在cookie中存必要的信息且越长度越小越好。在 写cookie的时候要记得给cookie设置一个合理的过期时间及域名,比如example.com上的cookie会同时被发送给 static.exmaple.com和www.example.com,所以如果cookie只对www域名有用就不要将其设在example.com 域名上。

25.Use Cookie-free Domains for Components 

在请求一个图片的时候带上cookie信息是毫无用处的,所以这种请求头中应该避免发送 cookie, 这就需要将静态文件和动态内容分布在不同的域名上,因为如果一个域名下有cookie,那么浏览器在向这个域名的server发送请求时就会带上 cookie,所以我们应该将cookie与静态文件放在不同的域名上,比如cookie在www域名下而静态文件在static域名下。

26.Minimize DOM Access 减少dom操作

减少js对dom的操作,因为这会触发浏览器的reflow和repaint,是比较耗时和耗cpu的事。关于reflow和repaint,简单来说就 是,页面在渲染过程中,伴随着css,js和dom的解析会多次触发元素的repaint和reflow事件,并将计数后的最终结果呈现给用户。此后,伴 随用户的一些操作可以会引起某些元素的repaint或reflow。

repaint: 不改变布局,只是元素本身重绘,例如改变一个元素的color或background-color等,如果一个父元素的color改变了,它的子元素应该也要被重绘,因为color是可以继承属性;

reflow: 重新布局,这个操作的消耗比repaint要大,因为需要重新计算元素及其子孙元素、祖先元素的位置,并一一重绘。

所以为了提高性能,应该尽量减少对dom的操作。一定要要通过js操作dom时,请遵循下面3点规则:

1.将dom节点放在一个引用中,例如var a  = document.getElementById("#a"); 以后通过变量a来操作节点#a,而不是每次都去getElment一下;

2.将节点“离线”后再操作,所谓离线,即将元素从dom tree中删除或设置其display为none.修改完成后再追加回dom tree或设置display:block; (关于这一点,我不太明白,从dom tree中删除节点或设置其display为none难 道不会引起reflow么?应该也是会的。这种方法应该只是对于会触发页面频繁reflow的操作有改善作用,对于只会触发一次reflow的操作个人认 为没什么优化作用。),还有一种方式是通过documentFragment来添加元素,例如我们需要添加10个p标签,那么比其以前需要调用10次 document.append()方式,我们可以用创建一个documentFragment节点,先将p添加到这个fragment中,然后再将fragment添加到dom tree中,这样只会引起dom tree的一次reflow. 可以参考http://www.cnblogs.com/yunfour/archive/2011/06/21/2085911.html

3.避免通过js修改元素的定位。这点不是太理解。例如我们要做一个动画,不通过js怎么更新元素的位置?所以这点不赞同。但是我们可以对此做优化,即: 将要动画的元素的position设置为absolute,使其脱离文档流,这样该元素位置的改变就不会引起其它元素的reflow.

27.Develop Smart Event Handlers 绑定”聪明”的事件监听

绑定“聪明”的事件监听:如果多个元素对同一事件具体相同的响应,则与其将事件监听一一绑定在各个元素上,我们可以将事件监听绑定在它们的父元素上,而后通过事件冒泡将事件委托给其父元素处理。 

以前我们都是在page的onload之后才开始执行动作,但实际上我们并不需要等那么晚,我们所需要的,只是保证在我们执行动作时我们所需的元素已经渲染完成了,所以我们可以在DOMContentLoaded 事件中执行我们的代码,但是DOMContentLoaded事件目前还没有被所有浏览器实现,所以目前可以使用 YUI EventonAvailable方法。(这个需要后期研究下怎么用)

28.Choose <link> over @import 使用link方式引用样式表,避免使用@import方式

不要在css中使用@import,因为会延迟css的加载,IE中,使用@import引用的css文件与将该css放在页面底部的效果是一样的。(有待研究)

29.Avoid Filters 避免使用滤镜

避免使用filter滤镜,该滤镜是IE为解决IE6中半透明图片而提供的一个解决方案,但是该滤镜会阻塞页面的渲染且会消耗过多的cpu资源。

值得一提的是,fillter滤镜不是通过改变图片来达到目的,而是通过改变html元素,所以它会对所有应用了滤镜的元素计算一次,即使所有的元 素应用的是同一滤镜。(即如果有10个div,它们应用了一个相同的class,该class中定义的背景图片使用了filter,那么该滤镜将被计算 10次而不是1次!!)

除此之外,还有一点需要注意:filter并不会阻塞并行下载。浏览器其实在后台还在下载其他网页文件,但没有进行渲染。你可以这样认为:IE不会渲染任何元素,直到所有的CSS下载结束(更多信息)。就是因为CSS中有一个图片的依赖于滤镜加载,所以CSS被认为没下载结束,导致IE不去渲染页面,直到依赖滤镜的图片被加载到。

更详细的信息可以参考这篇文章,写得很不错,推荐大家看看。

30.Optimize Images 优化图片

优化图片。在发布网站前,可以检查下你网站中所用到的图片,看看是否还有优化的空间。

比如一张只有几种颜色的小图片,却应用了16位颜色,就完全可以优化为8位的; (这点我已验证,采用更少的颜色确实可以减少文件的大小)

将gif格式的图片转换为png8的基本不会损失质量却可以减小文件大小;(这点我已验证,确实如此)

另外文中还推荐了imagemagick ,pngcrush ,jpegtran 这几个工具,简单了解了下,都是命令行工具,但具体用法我目前还没有研究,大家有兴趣可以先自己了解下,日后如果研究明白会再跟大家分享。

31.Optimize CSS Sprites

优化css sprite:

1.将多张图片垂直合并往往比水平合并生成的图片要小;(这一点在原文中正好说反了,说是水平合并的图片比较小,但经我验证,是垂直的比较小,大家可以自己试试)

2.将类似颜色的图片放在一起可以减少颜色数量,从而降低图片大小(这点应该是说将相近颜色的图片合并在一起,因为颜色相近,颜色位数就可以少些);

3.图片与图片之间的间隙不要太大,虽然这对降低文件大小没有太大的帮助,但是却可以减少客户端解压图片时的cpu消耗。

32.Don't Scale Images in HTML 使用合适尺寸的图片

如果你只需要一个小图,就不要传一个大图。例如你实际需要显示的是一个60*60的头像,就不要传一个100*100的然后再通过设置宽高将它缩小为60*60的。原因很简单,这样会消耗不必要的带宽和系统资源。

33.Make favicon.ico Small and Cacheable 将网站的favicon做的尽量小并且使之可以缓存

The favicon.ico is an image that stays in the root of your server. It's a necessary evil because even if you don't care about it the browser will still request it, so it's better not to respond with a 404 Not Found. Also since it's on the same server, cookies are sent every time it's requested. This image also interferes with the download sequence, for example in IE when you request extra components in the onload, the favicon will be downloaded before these extra components.

So to mitigate the drawbacks of having a favicon.ico make sure:

· It's small, preferably under 1K.

· Set Expires header with what you feel comfortable (since you cannot rename it if you decide to change it). You can probably safely set the Expires header a few months in the future. You can check the last modified date of your current favicon.ico to make an informed decision.

Imagemagick can help you create small favicons

将favico做得尽可能小,最好在1K以下;为之设置一个合理的过期时长。(关于favico还需要更多的研究,目前我有很多疑惑,因为在csdn的 html标签中我并没有看到link rel="shortcut icon",但实际上csdn的title上是有logo的; 另外我在有这个标签的网站的网络面板中也没有看到相应的请求)

首先制作一个16x16的icon图标,命名为favicon.ico,放在根目录下。然后将下面的代码嵌入head区: 

<link rel="icon" href="/favicon.ico" type="image/x-icon" /> 

或者 

<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /> 

或者 

什么代码也不用,浏览器也能够搜索出这个文件并显示出来。 (这种情况需要我们将图标放在网站根目录下,对java的项目来说就是webroot根目录下)

注意文件一定要命名为favicon ICO文件用专用软件转换而不能直接改后缀名。 

34.Keep Components under 25K 将组件的大小保持在25K以下(未压缩的情况下)

将所有想缓存的组件大小保持在25K以下,且是未压缩时的大小。因为iphone不会缓存大于25k的组件。(大家可以参看上面给的那篇文章,我目前还没看)

35.Pack Components into a Multipart Document 一次请求多个文件

在一个http请求中请求多个文件,淘宝的前端就是这么干的,如下面这条请求就一次请求了多个js文件:http://g.tbcdn.cn/tb/fp/1.0.3/fp/??second-screen-min.js,category-min.js,act-min.js,recom-min.js,global-shop-min.js,expressway-min.js,local-min.js,guide-min.js,footer-min.js?t=20130702

是通过nginx的combo实现的,一个nginx模块nginx-http-concat

关于nginx-http-concat可以参考 安装ngix和 concat说明
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  optimization