网站性能优化指南

虽然网络速度日益提高,但现在网站也越来越庞大复杂、资源也越来越大。如果只顾业务而欠考虑性能及体验等方面的问题,会流失许多用户。那应该从哪些方面来优化网页的性能呢?下面就结合最近读的《高性能网站建设指南》一书一起来了解网站优化的几个方向。

减少 HTTP 请求

  1. 图片地图

  2. CSS Sprites

  3. 内联图片

  4. 合并脚本和样式

利用 CDN

内容发布网络(CDN)是一组分布在多个不同地理位置的服务器,用于更加有效的像用户发布内容。例如:CDN 可能选择网络阶跃数最小的服务器,或者具有最短响应时间的服务器。

添加 Expires 头

在设计web页面的时候,首次访问的响应时间并不是唯一需要考虑的。页面初访者会进行很多 HTTP 请求,但通过使用一个长久的 Expries 头,可以使这些组件被缓存。这会在后续的页面浏览中避免不必要的HTTP请求。

压缩组件传输

如果 HTTP 请求不可避免,但响应包很小,传输时间就会减少,因为只需要将很小的包从服务器传递到客户端。这一效果对带宽较慢的宽带尤其明显。下面看如何使用 gzip 编码来压缩 HTTP 响应包,并由此减少网络响应时间。这是减少页面大小的最简单的技术,但影响是最大的。

  1. 压缩是如何工作的 从 HTTP1.1 开始,Web 客户端可以通过 HTTP 请求中的 Accept-Encoding 头表示对压缩的支持: Accept-Encoding:gzip,deflate 如果Web服务器看到请求中的这个头,就会使用客户端列出来的方法中的一种来压缩响应。web服务器通过响应中的 Content-Encoding 头来通知web客户端: Content-Encoding:gzip

  2. 压缩什么 服务器基于文件类型选择压缩什么,但这通常受限于对其进行的配置。一般压缩 HTML 文档,压缩脚本和样式表也是非常值得的,基本包括 XML 和 json 在内的任何文本响应。图片和 PDF不应该压缩,因为它们本来就被压缩过了。压缩也是有成本的,服务器需要额外的 CPU 周期来完成压缩,客户端要对压缩文件进行解压缩。根据经验,通常对大于1KB或者2KB的文件进行压缩。

  3. 节省 通常压缩能将响应的数据量降少减少近 70%。gzip 是典型的压缩选择。gzip 能将响应整体减少 66%,而 deflate 能减少 60%。gzip 能比 deflate 多压缩 6%。

  4. 代理缓存 当浏览器直接与服务器通信时,迄今为止所介绍的配置都能很好的工作。当浏览器通过代理来发送请求时,情况就变得复杂了。假设针对某个 URL 发送到代理的第一个请求来自一个不支持 gzip 的浏览器。这是到达代理的第一个请求,因此其缓存为空。代理会将请求转发到 web 服务器。此时服务器的响应是未经过压缩的。这个没有压缩的响应被代理缓存起来并发送给浏览器。现在,假设到达代理的第二个请求访问的是同一个URL,来自于一个支持 gzip的浏览器。代理会使用缓存中(未压缩)的内容进行响应,这就失去了进行压缩的机会。如果反序,情况会更严重。 解决问题的方法是在 web 服务器的响应中添加 Vary 头。Web 服务器可以告诉代理根据一个或多个请求头来改变缓存的响应。这将使得代理缓存响应多个版本。

CSS 扔在 HTML 最上面

组件通常是按照它们在文档中出现的顺序下载的。随着页面资源越来越多,我们打开一个页面第一眼(或许很久)看到很可能不是期待的内容而是白屏

  1. CSS at the Top 为了避免白屏,请将样式表放到文档顶部的 HEAD 中。"CSS at the Top",解决了这种错误情况。

  2. LINK 一个 STYLE 块可以包含多个 @import 规则,但 @import 规则必须放在其他规则之前。曾经因为 @import 中的规则没有生效而花费大把时间去修复?使用 LINK 标签来代替 @import 还能带来性能上的收益。(注:@import 规则可能导致白屏,即便 CSS at the Top)

  3. 无样式内容的闪烁 白屏是浏览器在尝试修改前端工程师所犯的错误——将样式表放在文档比较靠后的位置。白屏是对 FOUC 问题的弥补。浏览器可以延迟呈现,知道所有的样式表都下载完成之后,这就导致了白屏。反之,浏览器可以逐步呈现,但要承担闪烁的风险。这里没有完美的选择。

结论:使用 LINK 标签将样式表放在文档的 HEAD 中。

JS 扔到 HTML 最下面

使用脚本时,对于所有位于脚本以下的内容,逐步呈现都被阻塞了。将脚本放在页面越靠后的地方,意味着越多的内容能够逐步呈现出来。

  • 并行下载 对响应时间最大的是页面中组件的数量。对此解释要回到 HTTP 1.1 规范。该规范建议浏览器从每个主机名并行的下载两个组件。很多 Web 页面需要从一个主机名下载所有组件。 但增加并行下载数量并不是没有开销的,其优劣取决于你的带宽和 CPU 速度。(研究表明,使用两个主机名比使用1、4或者10个主机名能带来更好的性能)

  • 将脚本放在底部 放置脚本的最好地方是页面的底部。这不会阻止页面内容的呈现,而且页面中的可视组件可以尽早下载。

尽量少使用CSS表达式

CSS 表达式是动态设置 CSS 属性的一种强大(并且危险)的方式。对CSS 表达式的频繁求值使其得以工作,但也导致 CSS 表达式的低下性能。

  • 一次性表达式

  • 事件处理器

使用外部JS和CSS

  1. 纯粹而言,内联快一些 (前面讲了应减少HTTP请求的重要性)

减少DNS查询

Internet 是通过 IP 地址来查找服务器的。由于 IP 地址很难记忆,通常使用包含主机名的 URL 来代替,但当浏览器发送请求时,IP 地址然后是必需的。而 DNS 正是将主机名映射到 IP 地址上。然而,DNS 也是有开销的。通常浏览器查找一个给定的主机名的 IP 地址要花费20~120 毫秒,在 DNS 查找完成之前,浏览器不能从主机那儿下载到任何东西。

  • DNS 缓存和 TTL(Time-to-live)

  • 减少 DNS 查找

精简 JavaScript

前面已经讨论了压缩,其实除了压缩外删除不必要的字符以减少文件大小,也能改善加载时间。

  • 精简 精简是从代码中移除不必要的字符以减少其大小,从而改善加载shi'j时间的实践。在代码被精简后,所有的注释以及不必要的空白字符都将被移除。对于 JavaScript 而言,这可以改善响应时间效率,因为需要下载的文件大小变小了。

  • 混淆 混淆是可以应用在源代码上的另一种优化方式。和精简一样,它也会移除注释和不必要的字符,同时它还会改写代码。作为改写的一部分,函数和变量的名字将被转换为更短的字符串,这时的代码更加精炼,也更难阅读。

注:混淆是有缺点的。

gzip 压缩产生的效果最大,但是精简能够进一步减小文件大小。随着 JavaScript 的使用量和大小不断增长,精简 JavaScript 代码能够得到更多的节省。

少使用重定向

重定向会使你的页面变慢!

  • 重定向是如何损伤性能的 重定向会耗费更多时间,在重定向完毕并且 HTML 文档下载完毕之前,没有任何东西展示给用户。

  • 重定向之外的其他选择

避免重复脚本

前面讲了压缩和精简来减少文件大小,从而提高加载速度。但还有重复脚本这个问题存在。导致一个脚本重复有两个主要因素——团队大小和脚本数量。

  • 重复脚本损伤性能

  • 避免重复脚本

配置或移除ETag

减少呈现页面时所必须的 HTTP 请求的数量是加速用户体验的最佳方式,可以通过最大化浏览器缓存组件的能力来实现这一目标。

服务器在检测缓存的组件是否和原始服务器上的组件匹配时有两种方式——

  • 比较最新修改日期 当浏览器下载组件时,会将它们存储在缓存中。在后续的页面查看中,如果缓存未过期,浏览器就会从磁盘上读取它,避免产生 HTTP 请求。如果组件过期了,浏览器在重用它之前必须首先检查它是否有效。这称作一个条件 GET 请求。不幸的是浏览器必须产生这个 HTTP 请求,执行有效性检查,但这任比下载所有过期组件效率要高。

  • 比较实体标签

If-None-Match 比 If-Modified-Since 具有更高的优先级。你可能希望如果E-tag不匹配但最新修改日期是相同的,也能发送一个”304 Not Modified“响应,但实际并不是这样的。如果请求中同时出现这两个头,则原始服务器”禁止返回 304”,除非请求中的条件头字段全部一致

Ajax缓存

  • 什么是 Ajax 缓存

    Ajax在发送的数据成功后,会把请求的URL和返回的响应结果保存在缓存内,当下一次调用Ajax发送相同的请求时,它会直接从缓存中把数据取出来,这是为了提高页面的响应速度和用户体验。当前这要求两次请求URL完全相同,包括参数。这个时候,浏览器就不会与服务器交互。

  • Ajax 缓存好处

对一些静态页面内容的请求,比如图片,css文件,js脚本等,变得更加快捷,提高了页面的响应速度,也节省了网络通信资源。

参考

https://book.douban.com/subject/3132277/

Last updated