高性能网站建设指南

参考 https://blog.csdn.net/datou0529/article/details/80490180

参考 https://blog.csdn.net/CHS007chs/article/details/81628668

规则1:减少HTTP请求

  1. 图片地图:

    在一个图片上关联多个url,目标url的选择取决于用户点击了图片上的哪个位置。


    示例1
  2. css spirits
    示例2

    也可以合并图片,但更为灵活。

    <style type="text/css">
        #navbar span {
            width: 31px;
            height: 31px;
            display: inline;
            float:left;
            background-image: url(/img/sprite.gif);
        }
        .home {background-position: 0 0; margin-right: 4px; margin-left: 4px;}
        .gifts {background-position: -32px 0; margin-right: 4px;}
        .cart {background-position: -64px 0; margin-right: 4px;}
        .settings {background-position: -96px 0; margin-right: 4px;}
        .help {background-position: -128px 0; margin-right: 0;}
    </style>
    
    <div id="navbar" style="background-color: #F4F5EB; border: 2px ridge #333; width:180px; height: 32px; padding: 4px 0 4px 0">
        <a href="javascript:alert('Home')"><span class="home"></span></a>
        <a href="javascript:alert('Gifts')"><span class="gifts"></span></a>
        <a href="javascript:alert('Cart')"><span class="cart"></span></a>
        <a href="javascript:alert('Settings')"><span class="settings"></span></a>
        <a href="javascript:alert('Help')"><span class="help"></span></a>
    </div>

    css sprites还可以通过合并图片减少http请求,还降低了下载量,虽然有人会认为合并后的图片比分离的图片总和要大,但实际上合并后的图片会比分离的图片总和要小,因为它除低了图片自身的开销(颜色表,格式信息等)。

  3. 内联图片:通过data:URL模式可以在Web页面中包含图片但无需任何额外的http请求,同时可能存在数据大小上的限制。由于data:URL是内联在页面中的,在跨越不同页面时不会被缓存,所以不要去内联公司的logo。
    示例3
  4. 合并脚本和样式表

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

内容发布网络cdn: 分布于不同地理位置的服务器。

  • 优点:可缩短响应时间,备份、扩展存储能力、缓存,可缓和流量峰值压力
  • 缺点:响应时间受cdn服务提供商环境影响;无法直接控制组件服务器

cdn服务器一般用于静态内容,如图片、脚本、样式表、flash等。

规则3:添加Expires头

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

1.作用

web服务器使用Expires头来告诉web客户端它可以使用一个组件的当前副本,直到指定的时间为止。HTTP规范中简要的称该头为“在这一日期之后,响应被认为是无效的”,它在HTTP响应中发送。

如果页面中的一个图片返回了这个头,浏览器在后续的页面中会使用缓存的图片,将HTTP请求的数量减少一个。

2.缺点

它要求服务器和客户的时钟严格同步,另外,过期日期需要经常检查,如果过期后,还需要在服务器配置中提供一个新的日期。

3.另一种选择

Cache-Control: 【Cache-Control:max-age=315360000】

Cache-control使用max-age指令指定组件被缓存多久,它以秒为单位定义了一个更新窗。

4.更新的方法

Expires头会使用浏览器直接从硬盘上读取组件而无需生成新的http流量。因此,即使在服务器上更新了组件,已经访问过网站的用户也不大可能获取新的组件。为了确保用户能获取组件的最新版本,需要在所有html页面中修改组件的文件名:最有效的方案是修改所有链接,比如可以嵌入版本号。

规则4:压缩组件

web客户端可以通过http请求的Accept-Encoding头来表示对压缩的支持:

Accept-Encoding: gzip,deflate

如果web服务器在请求信息中看到这个头信息,它就可以通过响应的Content-Encoding头信息来返回服务器可用的压缩方式。

Content-Encoding: gzip

1.压缩什么

基于文本的资源如html,js ,css, xml都适用于压缩,然后对于图片而言,却不应该对图片进行压缩,因为图片本身已经被压缩过了,如果再进行gzip压缩,有可能得到的结果是和图片本身大小相差不大或更大,这样就浪费了服务器的CPU资源来做无用功了。

2.代理缓存的问题

浏览器直接与服务器通信,基于Accept-Encoding都可以很好的工作。但如果通过代理,这种情况下,压缩就要考虑额外的东西。

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

解决这一问题的方法就是在Web服务器的响应中添加Vary头

Vary:Accept-Encoding

表示web服务器告诉缓存服务器分别为每一个Accept-Encoding请求头缓存。

规则5: 将样式表放在顶部

  1. ie中,将样式表放到文档底部,导致白屏的情形,其他情况承担fouc风险(firefox都是选择承担fouc风险)

    • 新窗口打开时
    • 重新加载
    • 作为主页
  2. 将css放在文档顶部,可避免白屏
  3. 一个style块可以有多个import,但是必须放在其他规则之前。
  4. import规则可能会导致白屏现象,即便把import放在文档head中也是如此。
  5. 使用import会导致下载的无序性,使用link标签将样式表放到文档的head中
  6. 无样式的内容闪烁 flash of unstyled content (fouc):已经加载的文档重会导致的
  7. 白屏与fouc: 将样式表放到文档末尾,浏览器延迟呈现,避免fouc,则会导致白屏;反之,若浏览器逐步呈现,则有fouc的风险。解决办法:遵循html规范,将css放在顶部,即文档head中
  8. 样式表在页面并不会影响下载时间,但是会影响页面呈现。
  9. 将样式表放在文档底部会导制在浏览器中阻止内容逐步呈现,为避免当样式变化时重绘页面中的元素,浏览器会阻塞内容逐步呈现。
    1. link标签:
          <link rel="stylesheet" href="style.css">
                  2. @import规则:
          <style>    
            @import url("style.css");
          </style>

 

规则6: 将脚本放在底部

  1. 好处:页面可以逐步呈现,也可以提高下载并行度
  2. 使用css,页面逐步呈现会被组织,直到所有样式表下载完成。(放在head中的原因)
  3. 使用脚本,对于所有位于脚本以下的内容,逐步呈现都被阻塞了。
  4. 浏览器会并行的执行http请求,但是同一主机下的数量有限,因此会发生等待。
  5. 脚本阻塞下载原因:

    -) 脚本可能使用document.write修改页面内容
    -) 无法保证按照正确的顺序执行,因此导致报错

  6. 无法将脚本移至底部的情形:使用document.write对页面进行了修改,作用域问题等。

  7. 延迟脚本defer: defer属性表明脚本不含document.write,浏览器可以继续呈现。如果一个脚本可以延迟,则可以移到页面顶部。在firefox中,即便是延迟脚本也会阻塞呈现和并行下载。

规则7: 避免css表达式

ie支持expression,而其他浏览器不支持,如下:

   width:expression(document.body.clientWidth<600?"600px":"auto"); //js表达式,仅适用IE,后果CSS性能低下
min-width:600px;//other

表达式的求值频率太高了,它们不止在页面呈现和大小改变时求值,当页面滚动、甚至鼠标拖拽都要求值。

解决方法:

1.一次性表达式

2.事件处理器。

规则8:使用外部Javascript和CSS

外部CSS/JS和内联CSS/JS的区别:

  • 外部CSS/JS可以缓存;
  • 内部CSS/JS可以减少HTTP开销,更快加载;
  • 经常访问,使用外部CSS/JS更佳;
  • 高完整缓存率,使用外部CSS/JS更佳;
  • 每个页面都使用相同的CSS/JS,则使用外部CSS/JS更佳;
  • 主页: 仅有一个页面查看,每次都是空缓存,组件重用率低 ==》内联更佳
  • 加载后下载 post-onload download: 文档onload事件1s延迟之后,确保页面呈现完毕后才会下载js/css文件
  • 动态加载技术 dynamic inlining: 利用cookie是否存在,判断是否有缓存,有cookie则存在缓存,使用外部CSS/JS,如果没有,则使用内联CSS/JS。

结论:重用度很高,使用外部CSS/JS,否则使用内部

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

  1. DNS开销 查找一个给定服务器的IP地址要花费20~120毫秒,DNS查找完成前,浏览器不能从主机那里下载任何东西
  2. DNS缓存:ISP/局域网的特殊缓存服务器,操作系统的DNS缓存、浏览器缓存。当浏览器丢失了记录时,才会请求操作系统询问地址;
  3. 存活时间TTL:返回的DNS请求包括这个值,告诉客户端可以缓存多久。但浏览器通常忽略该值,通过keep-Alive覆盖时间限制,同时DNS记录的数量也有限制,而不管缓存记录的时间。超过了限制,早期的访问记录会被删除。客户端收到的平均TTL值一般为最大TTL值的一半,由于DNS解析器自身也拥有与DNS记录相关的TTL.
  4. IE中记录和查看dns的: ipconfig /displaydnsipconfig /flushdns
  5. 减少DNS查找与增加并行下载的平衡: 至少两个主机,不超过4个
    结论:通过使用keep-alive和较少的域名,减少dns查找

规则10:精简JavaScript

  1. 精简(Minification): 从代码中移除不必要的字符以减少其大小,进而改善加载时间。如:空白符(空格、换行、制表符)
  2. 混淆(Obfiscation): 与精简一样,会移除注释和空白,同时还会改写代码。改写:函数和变量名会变成更短的字符串,代码更加精炼,更难阅读,增加反向工程的难度。
  3. 混淆的缺点:缺陷 由于混淆更加复杂,混淆过程本身很有可能引入错误;维护 混淆会改变js符号,对于不能更改的需要进行标记 调试 代码难以阅读,增加调试难度
  4. gzip压缩产生影响最大,但精简能进一步减小文件大小
  5. 精简CSS带来的节省小于JS,因为通常css注释和空白,比js少。本质的优化在于合并相同的类,移除不使用的类

规则11:避免重定向

  1. 重定向原因:网站重新设计、跟踪流量、记录广告点击、建立易于记忆的URL。 重定向会使页面变慢
  2. 浏览器会自动将用户带到location字段的url,通常301和302响应不会被缓存,除非有附加头expires或cache-control要求这么做;
  3. meta重定向 <meta http-equiv="refresh" content="0; url=http://www.baidu.com"> 0s后重定向
  4. js重定向,将document.location设置为期望的url即可。
  5. 为确保后退按钮正确工作,最好使用3XX HTTP状态码
  6. 缺少结尾的斜线http://www.baidu.com/,很多web服务器会发送重定向,包括apache。原因为:允许自动索引,自动转到默认的index.html上。
  7. 跟踪内部流量:若同一家网站之间的流量,通过建立Refer日志来避免重定向。
  8. 跟踪出站流量:http://www.baidu.com***http%3a//en.wikipedia.org 会返回302. 使用信标 beacon,信标响应通常是1px*1px的透明图片,并在图片的url中包含要跟踪的信息(实际只需使用xmlHttpRequest readyState=2时确认已发送即可响应请求,或者使用新打开标签页或者弹出页target='_blank'即可。)
    代码示例
        300     Multiple Choices (基于Content-type)
        301     Moved Permancently
        302     Moved Temporarity(亦作Found)
        303     See Other(对302的说明)
        304     Not Modified    并非真的重定向,用来响应条件GET请求,避免下载已经存在于浏览器缓存中的数据
        305     Use Proxy
        306     (不再使用)
        307     Temporary Redirect(对302的说明)

规则12:删除重复脚本

  • 导致脚本重复的原因: 团队大小和脚本数量
  • 重复执行,重复下载(可通过缓存解决)

规则13:配置ETag

  1. ETag: Entity Tag 实体标签,是web服务器和浏览器用于确认缓存组件的有效性的一种机制。浏览器通过返回的expires判断缓存是否新鲜;如果过期了,浏览器在重用它之前首先得检查它是否仍然有效,这称作 条件get请求。如果浏览器缓存的组件是有效的,则服务器不会返回整个组件,只会返回304。
  2. 服务器在检测缓存组件是否和原服务器组件一致时,有两种方式:比较最新修改日期(服务器响应last-modified,浏览器使用if-modified-since回传服务器进行比较,若比较一致,则返回304)、比较实体标签(http1.1中引入,唯一标识一个组件的一个版本的字符串,需要以引号引起来,服务器响应ETag, 浏览器if-none-match回传到服务器进行比较,若匹配,返回304)。
  3. etag的意义:提供了一个比最新修改时间更灵活的机制。
  4. etag的问题:对服务器集群、代理来说,etag会不匹配,降低缓存效率
  5. if-none-match比if-modified-since有更高的优先级。
  6. 即便配置了很长的expires头,当用户reload或者refresh时,仍会产生条件get请求。如果需要通过除最新修改日期之外的一些东西来验证,则etag是一种强大的方法,否则最好简单的移除(etag性能问题)。
    结论:需要配置或者直接移除etag.

规则14:使Ajax可缓存

posted @ 2019-01-03 00:13  luanxm  阅读(124)  评论(0)    收藏  举报