《高性能网站建设指南》笔记

 

规则1:减小HTTP请求

        1. 图片地图(map)javascript

        2. CSS Spritesphp

        3. 内联图片  data:[<mediatype>][;base64],<data>css

        4. 合并脚本和样式表html

规则2:使用内容发布网络(CDN)

规则3:添加Expires头

        更新方法:修改连接/组件文件名(好比设置版本号)java

规则4:压缩组件(gzip)

规则5:将样式表放在顶部(使用link标签将样式表放在文档head中)

规则6:将脚本放在底部

规则7:避免CSS表达式

        (IE:expression【推荐一次性表达式/事件处理器】)web

规则8:使用外部JavaScript和CSS

规则9:减小DNS查找

        经过keep-alive和较少的域名来减小DNS查找数据库

规则10:精简JavaScript (精简、混淆)

规则11:避免重定向

规则12:  删除重复脚本

规则13:配置ETag(配置或移除ETag)

规则14:使Ajax可缓存

 


 

绪言A:


 

  至少有80%的时间花在了显示Web页面上,而且这些时间是花在html文档下载完毕后发生的。express

 

14条规则:


 

 

规则1: 减小http请求


 

  方法:编程

    1. 图片地图(Image Map):在一个图片上关联多个url,目标url的选择取决于用户点击了图片上的哪一个位置。后端

      图片地图有两种类型:服务器端图片地图(将全部点击提交到同一个目标url,向其传递用户点击的x,y坐标。Web应用程序将该x,y坐标映射为适当的操做)和客户端图片地图(将用户的点击映射到一个操做)。映射经过html的map标签实现。

      缺点:在定义图片地图上的区域坐标时,若是采用手工的方式则很难完成且容易出错,并且除了矩形意外没法定义其余星座。经过dhtml建立的图片地图则在ie中没法工做。

    2. CSS Sprites

      也能够合并图片,但更为灵活。

      方法:使用同一个背景图片,然而每一个元素有一个不一样的类,经过background-position属性指定了CSS Sprites的偏移量:

 1 <style type="text/css">
 2     #navbar span {
 3         width: 31px;
 4         height: 31px;
 5         display: inline;
 6         float:left;
 7         background-image: url(/img/sprite.gif);
 8     }
 9     .home {background-position: 0 0; margin-right: 4px; margin-left: 4px;}
10     .gifts {background-position: -32px 0; margin-right: 4px;}
11     .cart {background-position: -64px 0; margin-right: 4px;}
12     .settings {background-position: -96px 0; margin-right: 4px;}
13     .help {background-position: -128px 0; margin-right: 0;}
14 </style>
15 
16 <div id="navbar" style="background-color: #F4F5EB; border: 2px ridge #333; width:180px; height: 32px; padding: 4px 0 4px 0">
17     <a href="javascript:alert('Home')"><span class="home"></span></a>
18     <a href="javascript:alert('Gifts')"><span class="gifts"></span></a>
19     <a href="javascript:alert('Cart')"><span class="cart"></span></a>
20     <a href="javascript:alert('Settings')"><span class="settings"></span></a>
21     <a href="javascript:alert('Help')"><span class="help"></span></a>
22 </div>

      CSS Sprites还能够经过合并图片减小http请求,还下降了下载量。虽然会有人任务合并后的图片会比分离的图片总和要大,由于合并的图片中包含有附加的空白区域。实际上,合并后的图片会比分离的图片总和要小,由于它下降了图片自身的开销(颜色表,格式信息等)

    3. 内联图片

      data:[<mediatype>][;base64],<data>

      经过使用data:URL模式能够在Web页面中包含图片但无需任何额外的http请求。IE还不支持。同时可能存在数据大小上的限制。

      因为data:URL是内联在页面中的,在跨越不一样页面时不会被缓存,因此不要去内联公司logo

    4. 合并脚本和样式表

 

规则2: 使用内容发布网络(CDN,Content Delivery Network)


 

  若是应用程序Web服务器离用户更近,则一个http请求的响应时间将缩短。另外一方面,若是组件Web服务器离用户更近,则多个http请求的响应时间将缩短。

  概念:

    CDN是一组分布在多个不一样地理位置的Web服务器,用于更加有效地向用户发布内容。

  优势:

    1) 可缩短响应时间

    2) 有助于缓和Web流量峰值压力

  缺点:

    1) 响应时间可能会受到其余网站的影响。由于CDN服务提供商在其全部客户之间共享Web服务器组。

    2) 没法直接控制组件服务器所带来的特殊麻烦。

  CDN用于发布静态内容,好比图片、脚本、样式表和Flash。提供动态html页面会引入特殊的存储需求-----数据库链接,状态管理,验证,硬件和OS优化等。这些复杂性超过了CDN的能力范围。另外一方面,静态文件更容易存储并具备较少的依赖性。

 

规则3: 添加Expires头 


 

  【Expires: Thu,15 Apr 2010 20:00:00 GMT】

  做用: 

    Web服务器使用Expires头来告诉Web客户端它可使用一个组件的当前副本,直到指定的时间 为止。HTTP规范中简要的称该头为“在这一日期/时间以后,响应将被认为是无效的”。它在HTTP响应中发送。
    若是页面中的一个图片返回了这个头,浏览器在后续的页面浏览中会使用缓存的图片,将HTTP请求的数量减小一个。
 
   缺点:
    Expires头使用一个特定的时间,它 要求服务器和客户端的时钟严格同步
    另外,过时日期须要常常检查,而且一旦将来这一天到来了,还须要在服务器配置中 提供一个新的日期
 
   另外一种选择:Cache-Control:  【Cache-Control:max-age=315360000】
    Cache-Control能够克服Expires头的限制。
    Cache-Control使用max-age指令指定组件被缓存多久。它以秒为单位定义了一个更新窗。
 
   更新的方法:
    Expires头会使浏览器直接从硬盘上读取组件而无需生成任何新的http流量。所以,即便在服务器上更新了组件,已经访问过网站的用户也不大可能获取新的组件。为了确保用户能获取组件的最新版本,须要在全部html页面中 修改组件的文件名
    最有效的解决方案是修改其全部连接,这样,全新的请求将从原始服务器下载最新的内容。
    好比能够经过嵌入版本号
 

规则4: 压缩组件


 

   如何压缩:
    Web客户端能够经过http请求中的 Accept-Encoding头来表示对压缩的支持:
      Accept-Encoding: gzip,deflate
    若是web服务器在请求信息中看到这个头信息,它就能够经过响应的 Content-Encoding头信息来返回服务器可用的压缩方式。
      Content-Encoding: gzip
 
   压缩什么:
    基于文本的资源如html,js,css,xml都适用于压缩。然而对于图片而言,却不该该对图片进行压缩,由于图片自己是已经被压缩过了,若是再进行gzip压缩,有可能获得的结果是和图片自己大小相差不大或更大,这样就浪费了服务器的CPU资源来作无用功了。
 
   优缺点:
    优势:压缩组件能够减小Http响应时间,提高传输效率。
    缺点:服务器要经过花费额外的CPU周期来完成压缩,客户端要对压缩文件进行解压缩。
 
   代理缓存的问题
    浏览器直接与服务器通讯时,基于Accept-Encoding 均可以很好地工做。
    但若是经过代理:

      代理缓存服务器是一个中间层,位于客户端和服务器之间。使用代理缓存的状况下,浏览器将不直接与服务器通讯,而是经过代理发送请求。这种状况下,压缩就要考虑额外的东西了。

      首先,假设到达代理的是一个来自不支持gzip的浏览器的请求,代理会将请求转发到web服务器,此时web服务器的响应是未通过压缩的,这个响应会把代理服务器缓存起来并发给浏览器。如今,假设到达代理的第二个请求来自一个支持gzip浏览器,请求的是与以前相同的URL,代理会直接使用未经压缩的缓存响应,那么久失去了进行压缩的机会了。考虑更糟糕的状况,第一个请求来自支持gzip的浏览器,第二个请求来自不支持gzip的浏览器,这样第二个请求获得的缓存响应将没法被解码,致使出错。

      解决这一问题的方法就是在Web服务器的响应中添加Vary头,Vary:Accept-Encoding,表示web服务器告诉缓存服务器分别为每个Accpet-Encoding请求头缓存。在前面的例子中,代理经过识别Vary头,对响应缓存不一样的版本,避免出错。

    
 

规则5: 将样式表放在顶部(使用Link标签将样式表放在文档head中)


 

  将样式表放在文档底部会致使在浏览器中阻止内容逐步呈现。为避免当样式变化时重绘页面中的元素,浏览器会阻塞内容逐步呈现。
  两种方法:
     1. link标签:
      <link rel="stylesheet" href="style.css">
    2. @import规则:
      <style>    
        @import url("style.css");
      </style>
       @import规则可能会致使白屏,或组件下载时的无序性。
 

规则6: 将脚本放在底部


 

  使用并行下载:要考虑带宽和CPU速度。使用两个主机名更好
  脚本阻塞下载:然而, 在下载脚本时不可使用并行下载。这是为了保证脚本可以按照正确的顺序执行。
 

规则7: 避免css表达式


 

  CSS表达式适用于ie5及以后版本的支持。
     background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00");  //ie
  其问题在于:
    表达式的求值频率过高了。它们不止在页面呈现和大小改变时求值,当页面滚动、甚至鼠标拖拽都要求值。
  解决方法:
    1. 一次性表达式
    2. 事件处理器
 

规则8: 使用外部JavaSript和CSS


 

  纯粹而言,内联快一些。由于外部示例须要承担多个http请求带来的开销。
  可是!现实中仍是外部文件较快。 由于JS和CSS文件有机会被浏览器缓存起来
  
   主要权衡方法:
     页面浏览量:
      每一个用户产生的页面浏览量越少,则内联的更好。
    用户缓存外部组件的可能性——携带 完整缓存和空缓存的页面浏览量。
      若是网站本质上能够为用户带来更高完整缓存率,使用外部文件的收益就更大。若是不大可能产生完整缓存,则内联是更好选择。
  
     重用率
      此外,若是网站中每一个页面都使用了相同的js和css,使用外部文件能够提供这些组件的重用率,这时候使用外部文件更有优点。因此这时候还要考虑重用度。
  
   一箭双鵰的方法:
    1) 加载后下载:
      做为屡次页面浏览量中的第一次的主页,咱们但愿为主页内联Js和CSS,但又能为全部后续页面浏览量提供外部文件。这能够经过在主页加载完成后动态下载外部组件来实现(经过onload事件)。这可以将外部文件放到浏览器中的缓存中以便用户接下来访问其余页面。
    2) 动态内联:
      若是主页服务器知道一个组件是否在浏览器的缓存中,它能够在内联或使用外部文件之间作出最佳的选择。尽管服务器不能查看浏览器缓存中有什么,但能够用cookies作指示器。若是cookies不存在,就内联js和css。若是cookie出现了,则可能外部组件位于浏览器的缓存中,并使用了外部文件。
 

规则9: 减小DNS查找(经过使用Keep-Alive和较少的域名来减小DNS查找)


 

   DNS:将主机名映射到IP地址上。 同时,这也是开销。
 
   减小页面花在DNS查找上的时间的方法:
     DNS缓存和TTL
      将DNS查找缓存起来。
      影响DNS缓存的因素:
        TTL(Time-to-live, 存活时间):查找返回的DNS记录中含有这个值,该值告诉客户端能够对该记录缓存多久
     减小DNS查找
      当客户端的DNS缓存为空(浏览器和操做系统都是)时,DNS查找的数量与Web页面中惟一主机名的数量相等。这包括url,图片,脚本文件,样式表,Flash对象等的主机名。减小惟一主机名的数量就能够减小DNS查找的数量。
      可是,减小惟一主机名的数量就会潜在地减小页面中并行下载的数量。避免DNS查找下降了响应时间,单减小并行下载可能会增长时间。
      权衡之策:
        将这些组件分别放到至少2个,但不要超过4个主机名下。
     使用Keep-Alive:经过重用现有链接,从而经过避免TCP/IP开销来减小响应时间。
 

规则10: 精简JavaScript


 

   精简(Minification):
    是从代码中移除没必要要的字符以减少其大小,进而改善加载时间的实践。在代码被精简后,因此的注释以及没必要要的空白字符(空格,换行和制表符)都将被移除。对js而言,这能够改善响应时间效率,由于须要下载的文件大大减少了。
   混淆(Obfiscation):
    移除注释和空白,同时还会改写代码。做为改写的一部分,函数和变量的名字也将会被转换成更短的字符串,这时的代码更加精炼,也更难阅读。一般这样作的目的是为了增长对代码进行反向工程的难度,但这对提升性能而言也有帮助,由于这比精简更能减少代码的大小。
    缺陷:
      由于其更为复杂,混淆过程自己颇有可能会引入错误
    维护:
      因为混淆会改变js符号,所以须要对任何不能改变的符号(好比api函数)进行标记,防止混淆修改它们。
    调试:
      更加困难。
   其余方法减小js的时间:
    内联脚本:也应该精简。
    压缩和精简:
    精简css:
      优化css——合并相同的类,移除不使用的类等。
      移除注释和空白:好比使用缩写(“#666”代替“#666666”)和没必要要的字符串(“0”代替“0px”)
 

规则11: 避免重定向


 

   概念:
    重定向(Redirects)用于将用户从一个url从新路由到另外一个URL。
    状态码:3xx,最经常使用是301和302
   类型:当Web服务器向浏览器返回一个重定向时,响应中就会拥有一个范围在3xx的状态码。这表示用户代理必须执行进一步操做才能完成请求。几种3xx状态码:
1         300     Multiple Choices (基于Content-type)
2         301     Moved Permancently
3         302     Moved Temporarity(亦做Found)
4         303     See Other(对302的说明)
5         304     Not Modified    并不是真的重定向,用来响应条件GET请求,避免下载已经存在于浏览器缓存中的数据
6         305     Use Proxy
7         306     (再也不使用)
8         307     Temporary Redirect(对302的说明)

  

  重定向以外的选择:

    1. 一种重定向的发生状况:url的结尾必须出现斜线(/)而没有出现时

        当主机名后缺乏结尾斜线时是不会发生重定向的

    2. 用于:1)将旧url转移到新url,经过重定向整合代码库;2)将一个网站的不一样部分链接起来,以及基于一些条件(浏览器类型、用户帐号类型等)来引导用户

      替代方法:

        1)Alias, mod_rewrite和DirectorySlash要求除url外还要提交到一个接口(处理器或文件名),可是易于实现

        2)若是两个后端位于同一台服务器上,则它们的代码可能可以本身链接。利于,旧的处理器代码能够经过编程调用新的处理器代码

        3)若是域名变了,可使用一个CNAME(一条DNS记录,用于建立从一个域名指向另外一个域名的别名)让两个主机名指向相同的服务器。若是能作到这一点,这里提到的技术(Alias、mod_rewrite、DirectorySlash和直接链接代码)就是可行的。

    3. 用于跟踪内部流量: 重定向经常使用于跟踪用户流量的流向。

      替代方法:

        使用Referer日志来跟踪流量去向。(内部流量)

    4. 跟踪出站流量

      替代方法:

        1)使用信标(beacon)

        2)使用XMLHttpRequest

    5. 美化url:使用重定向使得url更加美观并易于记忆

      使用alias, mod_rewrite, DirectorySlash和直接连接代码来避免重定向

 

规则12: 删除重复脚本


 

   解决方法:
    1)在模板系统中实现脚本管理模块
    2)在php中建立一个称做insertScript的函数<?php insertScript("menu.js") ?>。 即判断该脚本是否被包含
  

规则13: 配置ETag


 

   定义:
    实体标签(Entity Tag, ETag)是Web服务器和浏览器用于确认缓存组件有效性的一种机制。
 
   组件如何被缓存和确认?
    1) Expires头:若是组件没有过时,那么它就是新鲜的。这取决于Expires头的值
    2) 条件get头:若是缓存的组件过时了(或者用户明确地从新加载了页面),浏览器在重用以前必须检查它是否仍然有效。这称做一个条件GET请求。若是浏览器缓存中的组件是有效的,原始服务器不会返回整个组件,而是返回一个“304 Not Modified”状态码。
      服务器在检查缓存的组件是否和原始服务器上的组件匹配时有两种方法:
        a. 比较最新修改日期: 经过Last-Modified响应头来返回组件的最新修改日期
        b. 比较实体标签: (“实体”是“组件”的另外一种称呼)。ETag是惟一标识了一个组件的一个特定版本的字符串。惟一的格式约束是该字符串必须使用引号引发来。
 
   ETag带来的问题:
    一般使用组件的某些属性来构造,这些属性对于特定的、寄宿了网站的服务器来讲是惟一的。当浏览器从一台服务器上获取了原始组件,以后,又向另外一台不一样的服务器发起条件GET请求时,ETag是不会匹配的。
    若是ETag不匹配,用户就会收到普通的200响应以及组件的全部数据。而对组件进行没必要要的从新加载还会影响服务器的性能并增长带宽开销。
    同时,ETag还下降了代理缓存的效率。
 
   解决方法:
    从ETag中移除changeNumber或彻底移除ETag。
 

规则14: 使Ajax可缓存(确保Ajax请求遵照性能指导,尤为应具备长久的Expires头【使响应可缓存】)


 

  1) 优化Ajax请求:
     规则3. 使响应可缓存(最重要)
    规则4. 压缩组件
    规则9. 减小DNS查找
    规则10. 精简JS
    规则11. 避免重定向
    规则13. ETag——用仍是不用
相关文章
相关标签/搜索