文章目录
  1. 1. 绪言
  2. 2. 规则1 - 减少HTTP请求
  3. 3. 规则2 - 使用内容分发网络(CDN)
  4. 4. 规则3 - 添加Expires头
  5. 5. 规则4 - 压缩组件
  6. 6. 规则5 - 将样式表放在顶部
  7. 7. 规则6 - 将脚本放在底部
  8. 8. 规则7 - 避免使用CSS表达式
  9. 9. 规则8 - 使用外部Javascript和CSS
  10. 10. 规则9 - 减少DNS查找
  11. 11. 规则10 - 精简Javascript
  12. 12. 规则11 - 避免重定向
  13. 13. 规则12 - 删除重复脚本
  14. 14. 规则13 - 配置ETag(Entity Tag)
  15. 15. 规则14 - 使Ajax可缓存

绪言

黄金法制: 只有10%~20%的最终用户响应时间花在了下载HTML文档上。其余的80%~90%时间花在了下载页面中的所有组件上。

规则1 - 减少HTTP请求

改善响应时间的最简单途径就是减少组件的数量,并由此减少HTTP请求的数量。

  1. 内联图片 data: [<mediatype>][; base64], <data>
    使用base64会使图片变大,应放在独立的CSS文件里面,使得可以缓存起来。

规则2 - 使用内容分发网络(CDN)

根据黄金法制, 使用距离用户更近组件web服务器, 比起使用离用户更近应用服务器来说,所获得的响应优化程度更大,也更容易实现。

  1. 有助于缓和Web流量峰值压力。
  2. 缺点: 容易受到使用相同CDN服务商的其它友商流量峰值的影响; 无法直接控制该组件(修改报头等)

规则3 - 添加Expires头

长久的Expires 头应该包含任何不经常变化的组件,包括图片、脚本、样式表和Flash组件(静态)。

  1. If-Modified-Since
    一次请求,客户端发送内容本地缓存的最后时间(If-Modified-Since)给服务器,服务器判断是否需要返回更新。
    ( N: 304 Not Modified;Y: 200 + 新内容, 客户端弃旧迎新)
  2. Expires(有效期至):
    客户端判断本地缓存是否过期, 不过期则不请求。
    【绝对时间】要求服务器与客户端的时钟严格同步。
  3. Cache-Control: max-age=xxxx
    客户端判断本地缓存是否过期, 不过期则不请求。
    【相对时间】指定组件被缓存多久(以秒为单位)
    HTTP 1.1 引入, 考虑到部分浏览器不支持 1.1, 建议同时指定 Cache-Control (优先被使用) 和 Expires
    注:mod_expires Apache模块, 使用Expires-Default, 到达响应时同时使用 Expires 头和 Cache-Control: max-age 头。
  4. 为确保用户能获取最新版本的组件,需及时修改组件的文件名。
    使用变量代表组件文件名而不是硬编码,减少变动时修改次数。

规则4 - 压缩组件

压缩通常能将数据量减少将近70%。

  1. 客户端使用 Accept-Encoding 头声明它支持压缩, 服务器使用 Conten-Encoding 头确认响应已被使用压缩。
  2. 图片和PDF不应该被压缩
  3. 代理缓存与 Vary: Accept-Encoding
    告诉代理服务器缓存两种版本的资源:压缩和非压缩,代理根据一个或多个请求头来改变缓存的响应,
    这有助于避免一些公共代理不能正确地检测 Content-Encoding 标头的问题。

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

浏览器逐步显示(尽快显示内容),会给用户提供可视化的反馈,改善了用户体验。

  1. 最佳实践:使用LINK标签将样式表放在文档的HEAD中
  2. 将CSS放在文档底部会导致(因浏览器而异):
    a. 白屏。在浏览器中阻止内容逐步呈现,延迟显示任何可视化组件。
    b. 无样式内容闪耀。浏览器也可以逐步呈现,但需要承担闪耀的风险(重绘DOM)。

规则6 - 将脚本放在底部

  1. 脚本会阻塞其后面内容的逐步呈现
  2. 脚本会阻塞对其后面组件内容的下载(防止脚本相互修改页面,保证脚本顺序执行与依赖关系)
  3. 最佳实践: 将脚本放置底部,先渲染内容,让组件并行下载。

规则7 - 避免使用CSS表达式

  1. expression 只有IE支持,它接受一个Javascript表达式。
  2. 表达式会非常频繁地求值,频繁地执行Javascript代码。
  3. 基本可以用Javascript事件监听去代替。

规则8 - 使用外部Javascript和CSS

  1. 使用内联JS和CSS可以减少HTTP请求数,请求速度上有优势,但外部JS和CSS优势在于可以被缓存(不变)
  2. 使用内联还是外部组件决战(访问量、空缓存vs完全缓存、组件重用率)
    主页较适宜使用内联(访问量大,组件重用率底,完全缓存百分比底)
  3. 根据实际情况进行折中拆分与合并JS和CSS
    • 合并多: 减少HTTP请求,合并数量多时,缓存命中率底(或需加载全部),适用于普通用户少跨页访问
    • 拆分多: 抽象,组件易重用,但请求多。适用于会话量高,访问不同页面多。
  4. 具体内联优势与缓存外部文件:
    a. 加载后下载(Javascript, window.onload关联加载外部组件的JS方法)
    b. 动态内联(根据cookies指示,动态生成HTML)

规则9 - 减少DNS查找

通过使用Keep-Alive和较少的域名来减少DNS查找

  1. 通常浏览器查找一个给定主机名的IP需要花费20~120ms, 在此之前不会下载任何东西(没有ip)
  2. 浏览器有自己的DNS缓存(也有对应的TTL,与DNS服务器不一致),查不到再到操作系统找。
  3. RFC建议避免使用过短的TTL,建议值为1天,但顶级网站为了做到快速故障转移,都将TTL值设置得比较小。
  4. 组件使用同个主机名可减少DNS查询,但会减少并行下载的数量。
  5. 使用Keep-Alive重用连接,避免重复DNS查询。

规则10 - 精简Javascript

  1. 精简是移除不必要的字符(空白、注释等)使得JS瘦身
  2. 混淆可抵制反向工程,较复杂,有可能会引入错误。

规则11 - 避免重定向

重定向会使页面变慢

  1. 301/302 响应在实际中不会被缓存,除非有附加的头 ExpiresCache-Control
  2. HTML重定向

    1
    <meta http-equiv="refresh" content="0; url=http://redirect.com">
  3. 重定向延迟了整个HTML文档的传输,所以说慢。

  4. 避免由于“缺少结尾斜线/”自动索引而产生的重定向(这是很多Web服务器的默认行为)。
  5. 减少由于后端重写导致的URL变化,新旧兼容的重定向。(采用Web服务器Alias,代码间跳转,CNAME等)
  6. 使用HTTP的referrer代替使用 301跳转的站内流量统计。
  7. 使用onclick绑定1px * 1px图片信标触发统计跟踪出站流量,而不是使用302统计后再跳转。

规则12 - 删除重复脚本

重复脚本损伤性能的方式: 不必要的HTTP请求(有缓存就不会)和多余执行Javascript的时间

  1. 避免包含多次脚本的方法: 在模板系统实现一个脚本管理模块。

规则13 - 配置ETag(Entity Tag)

ETag是Web服务器和浏览器用于确认缓存组件有效性的一种机制,是唯一标识一个组件特定版本的字符串。

  1. If-None-Match: "xxx-xxx-xx"If-Modified-Since 具有更高优先级
  2. 对于完全相同的组件,使用集群服务器时,不同的Web服务器产生的ETag不相同,缓存则不会命中。这也影响了代理服务器。
  3. 如非必要通过最新修改日期之外的东西来验证组件,最好移除ETag

规则14 - 使Ajax可缓存

确保Ajax请求遵守性能指导,尤其应具有长久的Expires头。

文章目录
  1. 1. 绪言
  2. 2. 规则1 - 减少HTTP请求
  3. 3. 规则2 - 使用内容分发网络(CDN)
  4. 4. 规则3 - 添加Expires头
  5. 5. 规则4 - 压缩组件
  6. 6. 规则5 - 将样式表放在顶部
  7. 7. 规则6 - 将脚本放在底部
  8. 8. 规则7 - 避免使用CSS表达式
  9. 9. 规则8 - 使用外部Javascript和CSS
  10. 10. 规则9 - 减少DNS查找
  11. 11. 规则10 - 精简Javascript
  12. 12. 规则11 - 避免重定向
  13. 13. 规则12 - 删除重复脚本
  14. 14. 规则13 - 配置ETag(Entity Tag)
  15. 15. 规则14 - 使Ajax可缓存