高性能网站建设指南 读书笔记3

规则9 - 减少DNS查找

Internet是通过IP地址来查找服务器的,由于IP地址很难记忆,通常用包含主机名的URL来取代它,但当浏览器发送其请求时,IP地址是必须的,这就是Domain Name SystemDNS)所处的角色。DNS将主机名映射到IP地址上,就将电话本将人名映射到他们的电话号码一样,当你在浏览器中输入www.baidu.com的时候,连接到浏览器的DNS解析器会返回服务器的IP地址。

如果一个服务器被另外一个具有不同IP地址的服务替代了,DNS允许用户使用同样的主机名来连接到新的服务器。(主机名相当于姓名,这种情况下相当于对应的电话号码更新了),或者可以将多个IP地址关联到一个主机名,为网站提高冗余度。(相当于存储了一个人的多个电话号码)

当然,DNS也是开销,通常浏览器查找一个给定的主机名的IP地址需要花费20-120毫秒,DNS查找完成之前,浏览器不能从主机名那里下载到任何东西。响应时间依赖于DNS解析器、它所承担的压力、你与它之间的距离和你的带宽速度。

DNS缓存

DNS查找可以被缓存起来以提高性能,这种缓存可以发生你的ISPInternet Service Provider 互联网服务提供商)或局域网中一台特殊的缓存服务器上,但我们这里要探索的是发生在独立用户计算机上的DNS缓存,在用户请求了一个主机名之后,DNS信息会留在操作系统的DNS缓存中,之后对于该主机名的请求将无需进行过多的DNS查找,至少短时间内不需要。

很多浏览器拥有其自己的缓存,和操作系统的缓存相分离。只要浏览器在其缓存中保留了DNS记录,它就不会麻烦操作系统请求这个记录。只有当浏览器缓存丢弃了记录时,它才会向操作系统询问地址——然后操作系统或者通过其缓存来响应这个请求,或许将请求发送给一台远程服务器,这时就会发生潜在的速度降低。而且浏览器对缓存DDS记录的数量也有限制,而不管缓存记录的时间。如果用户在短时间内访问了很多具有不同域名的网站,较早的DDS记录将被丢弃,必须重新查找该域名,虽然可能操作系统缓存还保留着这个记录,但是也比无需查找要慢。

TTL

服务器可以表明记录可以被缓存多久,查找返回的DDS记录包含了一个存活时间值(TTLTime-to-live),该值告诉客户端可以对该记录缓存多久。但是只有操作系统缓存会考虑TTL值,浏览器通常忽略该值,并设置它自己的事件限制。此外,HTTP协议中的Keep-Alive特性可以同时覆盖TTL和浏览器的时间限制,换句说,只要浏览器和web服务器愉快的通信着,并保持着TCP连接打开的状态,就没有理由进行DNS查找。

客户端收到的DNS记录的TTL值平均只有最大TTL值的一半,因为DNS解析器自身也拥有与DNS记录相关的TTL,当浏览器进行DNS查找时,DNS解析器返回的时间是其记录的TTL的剩余时间。如果最大TTL是300秒,DNS解析器可能返回的时间是1~300秒,平均150秒,对于给定的主机名,每次执行DNS查找时接受的TTL值都会变化。

window操作系统上的DNS缓存

window操作系统上的DNS缓存由DNS Client服务进行管理。你可以使用ipconfig命令来查看和刷新DNS Client服务:

ipconfig / displaydns
ipconfig / flushdns

重新启动也可以清空DNS Client服务缓存。重新启动浏览器会清空浏览器缓存,但不会清空DNS Client服务缓存。

IE上的DNS缓存

IEDNS缓存由三个注册表设置控制——DnsCacheTimeoutKeepAliveTimeoutServerInfoTimeout,可以创建在下面的注册表键下:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\InternetSettings\

IE中这三个设置的默认值是:

  • DnsCacheTimeout: 30分钟
    • IE一旦缓存了DNS记录就会使用30分钟作为TTL值,如果服务器返回了一个小于30分钟的TTL值,在IE中不会增加DNS查找的数量。
  • KeepAliveTimeout: 1分钟
    • 默认设置下,一个TCP连接将会一直使用,直到其被空闲1分钟为止,由于连接是持久的,所有无需DNS查找——Keep-Alive通过重用现有连接避免了重复的DNS查找。
  • ServerInfoTimeout: 2分钟
    • 该设置之后,即使如果没有Keep-Alive,如果一个主机名每2分钟重用了一次(被请求过),并且没有发生错误,也无需进行DNS查找(即使超过30分钟也可以)。

如果网络中心通过DNS来转移走流量,此时如果该IP还在运行,那么IE用户至少要等待30分钟才能更新DNS,而且IE的活跃用户(每两分钟访问一次)将会一直使用旧的IP地址而不会更新DNS直到发生错误。

FireFox

它具有如下的相关配置:

  • network.dnsCacheExpiration —— 1分钟
    • FF浏览器DNS缓存的记录比其TTL多1分钟,如果服务器返回的TTL值很小,很可能增加在FF中访问页面中的DNS查找次数。
  • network.dnsCacheEntries —— 20
    • 设置默认只有20条DNS记录能被缓,这意味着访问很多不同域名网站的用户访问时将会产生更多的DNS查找次数。
  • network.http.keep-alive.timeout —— 5分钟
    • 持久连接将一直保持,直到被空闲5分钟为止。

当客户端DNS缓存为空时,DNS查找的数量与web页面中的主机名的数量相等,这包括页面的URL、图片、脚本文件、样式表、Flash等的主机名,所以,减少主机名的数量就可以减少DNS查找的数量。

所以在将并行下载的时候说过,主机名不是越多越好,因为主机名越多,DNS查找的次数越多,但减少主机名潜在地减少了页面中并行下载的数量,所以在主机名和并行下载数量的设置上要有一个合适的取舍。

小结

1、为什么会有DNS查找?因为IP地址很难记忆,使用DNS可以将主机名映射到IP地址上,而且还可以关联多个IP地址。
2、使用DNS查找会发生什么?浏览器查找一个给定的主机名的IP地址需要花费20-120毫秒,在DNS查找完成之前,浏览器不能从主机名那里下载到任何东西。
3、DNS的缓存机制?在用户请求了一个主机名后,DNS记录会缓存在操作系统中,当然浏览器也拥有其自身的DNS记录缓存,只有当浏览器自身的DNS记录没有的时候,才会询问操作系统。如果此时操作系统也没有,就会发送请求到另一个远程服务器中获取新的DNS记录。
4、如何优化DNS查找次数?
+ 使用较少的域名(主机名)来减少DNS查找次数:因为每个域名都对应一个IP地址,都需要进行DNS查找。
+ 使用keep-alive来重用现有连接,减少DNS查找次数:因为浏览器和服务器保持着连接,则很明显的无需进行DNS查找。(我们已经同上电话了,就无需再去电话簿上找你的电话),浏览器和服务器通过Connection头来指出对keep-alive的支持,保持持久连接。

规则10 - 精简JS

精简是指从代码中移除不必要的字符以减小其大小,改善响应时间,进而改善页面加载时间。

混淆是可以应用在源代码上的另外一种方式,和精简一样,它也会移除空白和注释,同时它还会改写代码,作为改写的一部分,函数和变量名将被替换成更短的字符,这时的代码将更加精炼,也更难阅读,通常这样做是为了增加对代码进行反向工程的难度,同时也提高了性能,而且这比精简代码更能减小代码的大小。但是混淆也有缺点,混淆本身比较复杂,过程容易出错,混淆之后,代码在产品环境中更难阅读,更难调试(当然现在都可以使用构建工具来解决这两点)。

压缩和精简

gzip压缩对组件大小产生的影响最大,但精简能够进一步减小文件大小,随着JS的使用量和大小的不断增长,精简JS代码能够带来更多的节省。

精简CSS

精简CSS能够带来的收益通常要小于精简JS,因为CSS文件中的注释和空白通常比JS少,最大的节省通常来自于优化CSS——合并相同的类,移除不使用的等。不能够使用变量来代替,并且CSS依赖顺序的本质(层叠样式表)决定了想从这方面精简CSS这将是一个复杂的过程。

规则11 - 避免重定向

重定向(Redirect)用于将用户从一个URL路由到另一个URL,重定向有很多种——301和302是最常用的两种,通常针对HTML文档进行重定向,但也可能用在请求页面中的组件,使用重定向会有很多不同的原因,比如网站重新设计、跟踪流量、记录广告点击和建立易于记忆的URL,当然重定向会使你的页面变慢

web服务器向浏览器返回一个重定向时,响应中就会拥有一个3xx的状态码。这表示用户代理必须执行进一步的操作才能完成请求。

  • 300 Multiple Choices 基于Content-Type 多种选择
  • 301 Moved Permancently 永久移动
  • 302 Moved Temporarity 临时移动
  • 303 See Other 对302的说明,查看其它位置
  • 304 Not Modified 未修改
  • 305 Use Proxy 使用代理
  • 307 Temporary Redirect 临时重定向 对302的说明

301和302是使用最多的,303和307是HTTP 1.1规范中添加的用来澄清对302的使用,但是几乎没人使用。

HTTP 1.1 301  Moved Permancently 
Location: http://test.com/newurl
Content-Type: text/html

浏览器会自动将用户带到Location字段所给出的URL,重定向所必需的所有信息都处在在这个响应头中了,301和302在实际中都不会被缓存,除非有附加的头要求它这么做,比如ExpiresCache-Control

还有其他方法可自动将用户重定向其他URLHTML文档中的包含 meta refresh标签可以在其content属性指定的秒数后重定向用户


JS也可用于执行重定向,将document.location设置为期望的URL即可,如果你必须进行重定向,最好的技术是使用标准的 3xx HTTP状态码,这主要是为了确保后退按钮能够正常工作。

重定向是如何影响性能的,如果第一个HTTP请求是重定向,它会延迟整个HTML文档的下载,在HTML文档到达之前页面中不会呈现任何东西,也没有任何组件会被下载,延迟了用户期望的反馈。

什么时候会使用重定向?有没有优化方案?
1、缺少结尾的斜线

有一种重定向最为浪费、发生得也很频繁,但web开发人员通常没有意识到它,它发生在URL的结尾必须出现斜线/时而没有出现时。缺少结尾的斜线时发生重定向有着很充分的理由,它允许自动索引,自动转到默认的index.html上。当主机名缺少结尾斜线时不会发生重定向,因为浏览器在进行GET请求时必须指定路径,如果没有,它就简单地使用文档目录(/)。

2、连接网站

如果网站的后端被重写,新的实现中的URL很可能会有所不同,将用户从旧的URL转移到新的URL最简单的方式就是使用重定向,将旧网站连接到新网站只是重定向常见表现形式之一,其他形式还包括将一个网站的不同部分连接起来,以及基于一些条件(浏览器类型,用户账户类型等)来引导用户,使用重定向来连接两个网站很简单且只需要很少的代码。虽然重定向降低了开发的复杂性,但是损害了用户体验,所以可以用更多的开发工作来优化后端代码以减少这一部分的重定向。

3、跟踪内部流量

重定向经常用于跟踪用户流量的流向,例如,主页的nav导航到另一个功能页面,点击nav的时候,将用户先导航到专门记录web日志的页面,然后这个页面返回一个301响应,并且Location指向真正的功能页面,这时候就可以通过web日志得知用户在离开主页是去往了哪个功能页面。

优化选择是使用referer日志来追踪流量去向,当用户从页面导航到功能页面时,会携带一个referer值(表示来源页面的URL)去访问功能页面,这样就避免了向用户发送重定向,也就改善了响应时间,使用该方法的难处在于,要向对离开主页的流量进行统计,就必须分析所有功能页的日志。对于内部流量——同一家公司各个网站之间的浏览,值得通过建立referer日志来避免重定向,以此来节省时间。

4、跟踪出站流量

当你尝试跟踪用户流量时,你会发现链接可能将用户带离你的网站,在这种情况下,使用referer的方式就不太现实了,比如,使用搜索引擎搜索时,可以将每个搜索结果链接包装到一个重定向中来解决跟踪的问题,重定向一个专用的记录页面并将搜索结果链接带过去,然后在记录页面中返回302响应,将Location设置为搜索结果的链接。这样就能通过分析这个专用的记录页面来分析用户离开你的网站去了哪。

当然为了避免重定向,也有别的方法,使用信标当用户点击搜索结果链接时都要发送一个信标(http请求),信标响应通常是一个1px * 1px的透明图片,不过返回204更好,因为它更小,这通过为每个链接绑定onclick事件处理器来完成。这种该方法可能和使用重定向一样慢,因为这两种技巧都必须有一个额外的http请求。在跟踪弹出式广告的点击量,这种方式就很好。因为弹出式广告不会卸载当前页面,都是使用a标签的target="_blank"属性来打开新页面,这样图标请求就会顺利完成而不会被中断。

另一种方式使用 XMLHTTPRequest来发送信标,但在卸载页面之前只需要等到请求到达readyState 2(已发送)即可,无需等待响应,这比等待重定向的整个HTTP响应要快,也比一个完整的信标HTTP请求要快,但你必须决定是否有必要采用这么复杂的方式。

5、美化URL

使用重定向用来支持美观且易于记忆的URL。因为有的功能页面的html文件嵌套过深,或者说文件夹名过长,直接访问这个接口URL不太适合产品,所以用简单易记的URL去重定向到真正的URL用来优化用户使用。

小结

1、在重定向完成之前,真正想访问的那个页面的所有组件都不会开始下载,延迟了用户的期望反馈。
2、在需要使用重定向时,都可以寻找别的方案来替换,所以在开发工程中要尽量的避免使用重定向的方法来实现需求。

规则12 - 删除重复脚本

导致重复脚本的重复有两个因素——团队大小和脚本数量。由于来之不同团队的很多人共同开发,很容易有相同的脚本被重复添加,例如,两个贡献JS的开发者可能都需要管理Cookies,因此他们都添加了公司的cookie.js脚本,两个开发者都不知道对方已经向页面中添加了这个脚本。

重复脚本损伤性能的方式有两种——不必要的HTTP请求和执行JS所浪费的时间,不必要的HTTP请求只会发生在IE中,而不会发生在FF中,在IE中,如果脚本被包含两次且没有缓存,浏览器会在页面加载期间产生两个HTTP请求,即使脚本可以缓存,加载一次该页面可以填充缓存,用户刷新页面时,还是产生两个HTTP请求,尤其是产生了两个条件GET请求。

除了会产生不必要的HTTP请求,对脚本进行多次求值也会浪费时间,对JS进行多余的执行在IEFF中都存在,与脚本是否缓存无关。

总体来说:

  • 在页面中多次包含相同的脚本会使页面变慢
  • IE中,如果脚本没有被缓存,或在重新加载页面时,会产生额外的HTTP请求。
  • FFIE中,脚本会被多次求值。
  • 所以请确保脚本只被包含一次。

规则13 - 配置或移除ETag

减少呈现页面时所必需的HTTP请求数量是加速用户体验的最佳方式,可以通过最大化浏览器缓存组件的能力来实现这一目标,但当网站被宿主在多余一台服务器上时,ETag头可能会阻碍缓存。

ETag(Entity Tag实体标签)是web服务器和浏览器用于确认缓存有效性的一种机制,浏览器下载组件时,会将它们存储到缓存中,在后续的页面浏览中,如果缓存的组件是”新鲜的“,浏览器就会从磁盘上读取它,避免产生HTTP请求,如果组件没有过期,那它就是新鲜的,这取决于Expires的值。

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

HTTP规范建议服务器不应将Expires日期设置为未来一年之后,但这是一个指导原则,浏览器支持超过未来一年的Expires过期日期,对于不太会过期的组件(比如网站的logo),将过期日期设置的久远一些能够更有效的避免HTTP请求。

如果缓存的组件过期了(或者用户明确的重新加载了页面),浏览器在重用它之前必须首先检查它是否仍然有效,这称做条件GET请求(使用Expires头能避免HTTP请求),虽然这个HTTP请求也需要消耗时间,但是这比简单地下载已过期的组件效率要高,如果浏览器缓存中的组件是有效的,原始服务器不会返回整个组件,而是返回一个304状态码。服务器在检测缓存的组件是否和原始服务器上的组件匹配时有两种方式:

  • 比较最新的修改日期 Last-ModifiedIf-Modified-Since
  • 比较实体标签 ETagIf-None-Match

比较修改日期

// 第一次请求

// 请求头
GET /logo.gif HTTP 1.1
Host: us.test.com
// 响应头
HTTP 1.1 200 OK
Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT
Content-Length: 1195

// ========================

// 第二次请求
// 请求头
GET /logo.gif HTTP 1.1
Host: us.test.com
If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT
// 响应头
HTTP 1.1 304 Not Modified

比较实体标签

ETag提供了另外一种方式,用于检测浏览器缓存中的组件与原始服务器上的组件是否匹配,(”实体“是我们之前提到的”组件“的另一种称呼),在HTTP 1.1中引入,是唯一表示了一个组件的一个特定版本的字符串,唯一的格式约束是该字符串必须用引号引起来。

// 第一次请求

// 请求头
GET /logo.gif HTTP 1.1
Host: us.test.com
// 响应头
HTTP 1.1 200 OK
Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT
Content-Length: 1195
ETag: "10c24bc-4ab-457e1c1f"
// ========================

// 第二次请求
// 请求头
GET /logo.gif HTTP 1.1
Host: us.test.com
If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT
If-None-Match: "10c24bc-4ab-457e1c1f"
// 响应头
HTTP 1.1 304 Not Modified 

ETag的加入为验证实体提供了比验证最新修改日期更为灵活的机制,例如,如果实体依据User-AgentAccept-Language头而改变,实体的状态可以反映在ETag中,此后如果浏览器必须验证一个组件,它会使用If-None-Match头将ETag值传回原始服务器,如果匹配则返回304状态码,使响应较小。

优势
  • 有些URL是多语言的网页,相同的URL会返回不同的东西。还有不同的Session有不同的Cookie也就有不同的内容。这种情况下如果使用ProxyProxy就无法区分导致串门,只能简单的取消cache功能。Etag解决了这个问题,因为它能区分相同URL不同的对象。Etag在不同URL之间没有可比性,也就是不同URL相同Etag没有特别意义。
  • 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
  • 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是秒级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒)
  • 某些服务器不能精确的得到文件的最后修改时间;
缺陷

ETag字符串的生成,通常与组件的某些属性有关,这些属性对于特定的、寄宿了网站的服务器来说是唯一的,而当浏览器从一台服务器获取了原始组件之后,又向另外一台不同的服务器发起条件GET请求,ETag是不会匹配的,这对于使用服务器集群来处理请求的网站来说,这是一种很常见的情况,对于拥有多台服务器的网站,ApacheIISETag中嵌入的数据都会大大地降低有效性验证的成功率。

Apache 1.32.xETag格式是inode-size-timestamp,文件系统使用inode来存储文件类型、所有者、组和访问模式等信息,尽管在多台服务器上一个给定的文件可能位于相同的目录、具有相同的大小、权限、时间戳等,从一台服务器到另一台服务器,其inode仍然是不同的。IIS 5.06.0上的ETag有着类似的问题,IIS上的ETag的格式是Filetimestamp:ChangeNumberChangeNumber适用于跟踪IIS配置变化的计数器,对于一个网站背后的所有IIS服务器来说,ChangeNumber不大可能相同。

最后的结果是,对于完全相同的组件,从一台服务器到另一台,ApacheIIS产生的ETag是不会匹配的。如果不匹配,则不会返回304状态码,而是返回一个普通的200响应及组件的相关数据,如果你在一台服务器上寄宿网站,这不是问题,但你如果使用了服务器集群,则组件的下载次数可能会比必须进行下载的次数多得多,这将导致性能的下降,如果你拥有10台服务器,则用户只有10%的概率在第二次访问到相同的服务器,得到一个正确的304响应,其余90%的概率将会得到无用的200响应并下载所有的数据。

ETag还降低了代理缓存的效率,用户缓存的ETag经常和代理缓存的ETag不匹配,这导致不必要的请求被发送到原始器,这种情况下,用户和代理之间就不会产生304响应,而是会产生两个又慢又大的200响应,(原始服务器到代理的 和 代理到用户的),同时ETag的默认格式生成字符串可能还会引入安全问题。

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

ETag用还是不用

如果你在多台服务器上寄宿你的网站,而且你使用的是具有默认配ETag配置的ApacheIIS,你的用户将面对缓慢的页面,你的服务器会具有很高的负载,你会消耗大量的带宽,而且代理也不能有效的缓存你的内容,即使你为组件添加了长久的Expires头,一旦用户单击了ReloadRefresh按钮,依然会产生条件GET请求,对于ETag带来的问题你没有办法绕过它。

如果你的组件必须通过最新修改日期之外的一些东西来进行验证,则ETag是一种强大的方法,反之,你最好将其移除,ApacheIIS都将ETag视为一个性能问题,并建议修改ETag的内容,Apache 1.3.23版本之后都支持FileETag none 的指令来移除ETag中的inode值,只留下sizetimestamp作为组件的ETag,类似的IIS也可以为所有服务器设置相同的ChangeNumber,保留文件的时间戳作为ETag中仅有的另一块信息。遵从这一建议后,ETag中将只包含sizetimestampApache)或只有timestampIIS),这样,会有很多组件拥有相同的信息,所以最好还是将ETag完全移除,Last-Modified头可以提供完全等价的信息,而且移除ETag可以减少响应的时间和和后续请求的HTTP头大小。

小结

1、ETag被用来在服务器和浏览器之间确认组件缓存的有效性,使用ETag响应头和If-None-Match请求头来进行匹配。
2、If-None-MatchIf-Modified-Since优先级更高,如果请求中同时出现了这两个头,则原始服务器禁止返回304除非请求中的条件头字段全部一致。
3、优势:有些URL是多语言的网页,相同的URL会返回不同的东西,ETag能够区分相同的URL不同的对象;如果组件仅仅变化了修改时间,而没有修改内容,ETag也可以有效匹配来减少响应;而且If-Modified-Since能检查到的粒度是秒级的,如果1秒钟修改了N次这种修改将无法判断,ETag可以避免这个问题;有的服务器并不能返回准确的最新修改时间。
4、在使用服务器集群时,相同的组件每个服务器生成的ETag都不相同,这大大的增加了不必要HTTP请求的次数。而且默认的生成ETag的格式可能还会引发安全问题。
5、所以,如果必须使用ETag则请配置它,在Apache中移除ETaginode的值,在IIS中为所有服务器设置相同的ChangeNumber,但是最好建议你在不是必须使用时完全移除它。

规则 14 - 使Ajax可缓存

Web 2.0 、 DHTML 、Ajax

web2.0包含很多概念,其中之一就是DHTMLAjaxDHTML中的一项关键技术。web2.0的关键概念包括类似应用程序的用户界面(UI)和来自多个Web Service的聚合信息(数据)。web页面变得越来越像一个具有良好定义的输入、输出的应用程序。DHTMLAjax是实现这些概念的技术。

DHTML(动态HTML)允许在页面加载完毕后,HTML页面的表现能够变化(与用户交互),这使用JS与浏览器的文档对象DOM进行交互来实现。AjaxDHTML中使用的一项技术,客户端可以获取和显示用户请求的新信息而无需重新加载页面。

Ajax表示异步的JavaScriptXMLAsynchronous JavaScript and XML),它不是一个单独的、需要许可证的技术,而是一组技术。包含JSCSSDOM和异步数据获取,Ajax的目的是为了突破web本质的开始-停止的交互方式,向用户显示一个白屏然后重绘整个页面不是一种好的用户体验,而AjaxUIWeb服务器之间插入了一层,这个Ajax层位于客户端,与web服务器进行交互以获取请求的信息,并与表现层交互,仅更新那些必要的组件,它将web体验从”浏览页面“转变为”与应用程序进行交互“。

异步与即时

Ajax的一个明显优点就是向用户提供了即时反馈,因为它异步的从后端web服务器请求信息,但是使用Ajax,并不能保证用户能够”即时”的收到反馈,用户是否需要等待响应和页面更新取决于你如何使用Ajax,其中关键因素在于Ajax请求是被动请求还是主动请求,被动请求是为了将来使用而预先发起的,例如在一个基于webEmail客户端中,可能会使用被动请求在用户真正需要之前下载用户的地址簿,经过被动加载,当用户需要为一个Email消息添加地址时,客户端能够确保地址簿已经存在于缓存中。主动请求是基于用户当前的操作而发起的,例如查找所有与用户搜索条件相匹配的Email消息。

即便Ajax请求是异步的,用户可能仍需等待响应,不过用户不必去忍受整个页面的重新加载了,而在用户等待时,UI仍然是可以响应的,比如Loading。当然在用户在进行进一步操作之前仍可能需要坐在那里等待搜索结果显示出来,所以”异步“并不代表”即时“。

优化Ajax请求

当发起主动Ajax请求时,用户仍需等待,要改善性能,优化Ajax请求很重要,优化主动Ajax请求的技术同样适用于优化被动Ajax请求,但是主动请求对用户体验影响更大。改善这些主动Ajax请求最重要的方式就是使响应可缓存,就像规则3中的讨论,同样还有其他规则也适用于Ajax请求:

  • 规则4 - 压缩组件
  • 规则9 - 减少DNS查找
  • 规则10 - 精简JS
  • 规则11 - 避免重定向
  • 规则13 - 配置或移除ETag

然而规则3-使用缓存是最重要的。

现实世界中的Ajax缓存

例子:在启用一个Email的客户端时,可以被动请求下载前三个Email消息的正文,用户很有可能点击这些Email消息中的一个或几个,它们此时已经被下载到客户端,这意味着用户无需任何Ajax就能看到他的Email消息,当用户想查看一个不在前三个消息之列的Email消息,就会产生一个主动的Ajax请求,用户在阅读消息之前必须等待响应。之后假设用户离开了Email客户端并浏览了其他网站,然后返回并再次点击第4个Email信息,不出所料,会又一次发送完全相同的请求,所以可以使用一个长久的Expires头,来将响应缓存在磁盘中,优化用户体验,当然这对于开发者来说是违反只觉得,因为这应该是一个动态生成的响应,只包含与这世界上一个用户相关的信息,使浏览器缓存这些数据看上去没有任何意义,但是一个用户可能每天或者每周进行很多次对该Email消息的请求,如果你可以为他缓存响应,就会看到缓慢的和快速的用户体验之间的差距,使这些Ajax请求可缓存,除了改变HTTP头之外还需要进行更多的操作,响应的个性化和动态本质必须被反应到缓存中,可供采用的方式就是使用查询字符串,保证这个响应只对当前用户有效,可以将用户名放到查询字符串中来做到这一点。

响应可能因为数据隐私的原因不能被缓存。当数据认为是私有的时,大多会使用Cache-Control: no-store头,使用这个头之后,响应根本不会被写入到磁盘中,但是HTTP规范警告说不要依赖这一机制来确保数据的隐私性,恶意的或危险的缓存会完全忽略Cache-Control: no-store头。处理数据隐私性的另外一种方式就是使用安全通信协议如安全套接字层(Secure Sockets Layer, SSL)。

小结

1、Ajax是使用户能够无需等待整个页面的重新加载就可以与页面进行交互的技术。提高了用户的体验,所以优化Ajax请求十分重要。
2、优化Ajax请求的方式,最重要的就是时响应具有长久的Expires头,当然还有之前所提到的压缩组件、减少DNS查找、精简JS、避免重定向、配置或移除ETag

你可能感兴趣的:(高性能网站建设指南 读书笔记3)