摘要: Yahoo!网站性能最佳体验的34条黄金守则英文地址http://developer.yahoo.com/performance/rules.html 中文地址 http://www.dudo.org/article.asp?id=214 内容篇 http://www.dudo.org/article.asp?id=215 服务器篇 http://www.dudo.org/article.asp?...  阅读全文
posted @ 2009-04-24 10:26 YSLOW 中文介绍 阅读(212) | 评论 (0)编辑

英文原文地址

Ajax 缓存: 两个重要的事实文章中, 作者指出:

在IE中,即使你按强制刷新(Ctrl+F5),在内容过期之前,Ajax也不会更新。确保更新的唯一方法是从缓存中删除此记录。

我发现这虽然很难让人相信,但这确是事实。如果碰到刷新键(F5),IE浏览器将重新请求在网页中的除XMLHttpRequest以外所有未过期的资源。在测试期间,这肯定会为开发造成混乱,但我想知道是否还有其他问题。其他主流浏览器的行为是什么?如果内容已经过期或者没有Expires头的行为是什么?增加Cache-Control: max-age 头有什么效果?

因此我创建了这个Ajax 缓存测试页面.

这个测试页面包含了一个图片,一个外部脚本文件和一个XMLHttpRequest。过期日期取决于我们选择的链接。

  • Expires in the Past 包含了一个已过期30天的Expires 响应头, 一个Cache-Control: max-age=0 响应头
  • no Expires没有返回任何Expires 或 Cache-Control 响应头
  • Expires in the Future 包含一个在未来30天才过期的Expires 响应头, 一个Cache-Control :max-age=2592000 响应头.

测试很简单: 点击一下链接 (比如, Expires in the Past), 等待页面加载完毕,然后按F5。表1展示了在主流浏览器下的测试结果。结果记录了Ajax请求是否重新请求还是从缓存读取,如果重新请求HTTP状态码是什么。

表1 当Ajax被缓存,按F5的结果
Past Expires No Expires Future Expires
Chrome 2 304 304 304
Firefox 3.5 304 304 304
IE 7 304 cache cache
IE 8 304 cache cache
Opera 10 304 cache 304
Safari 4 200 200 200

下面是我对按F5键的总结:

  • 所有浏览器均重新请求图片和脚本。(这样做是有道理的)
  • 所有浏览器均重新请求ajax,如果已经过期。 (这样做是有道理的 - 浏览器已经知道了缓存的Ajax已经失效)
  • 唯一不同的行为是当Ajax没有设置Expires缓存头或缓存未到期时. 即使按Ctrl+F5,IE 7和8 均重新请求Ajax,不管没有Expires头或没有过期。 当没有Expires头时,Opera 10 重新请求Ajax 。(我没有找到在Opera下强制刷新的功能)
  • 所有情况下,Opera 10 和 Safari 4 重新请求favicon.ico(浪费)
  • 所有情况下,Safari 4 均没有发送If-Modified-Since头,导致产生HTTP 200状态码,对于图片和脚本也是一样(这是浪费并且背离了其它浏览器的行为)

结论

下面是我对页面开发人员和浏览器厂商的建议:

  1. 开发人员需要设置一个已过期或未过期的Expires,避免出现未指定Expires时含混不清和怪异的行为
  2. 如果Ajax不应被缓存,开发人员应该设置一个已过期的过期日期
  3. 如果Ajax应该被缓存,开发人员应该设置一个未过期的过期日期。当在IE 7和8下面测试时,开发人员应该记得测试重新加载(F5)时清空缓存
  4. 当按F5时,IE 应该重新请求Ajax
  5. 当按F5时,Opera 和 Safari 应该不再加载favicon.ico
  6. 当按F5时,Safari应该发送If-Modified-Since头
posted @ 2009-08-28 15:54 YSLOW 中文介绍 阅读(71) | 评论 (0)编辑

英文原文地址

Ajax调用就像任何其他的HTTP请求一样可以用来构建一个网页。然而,由于其动态的性质人们常常忽略了可以缓存它们而从中受益。

高性能网站建设第14条规则:

缓存Ajax

确保您的Ajax请求遵循这条规则,特别是包含一个Expires头.

这个博客帖子的其余部分包括两个重要的事实,将帮助您理解并有效应用Ajax缓存

事实1 : Ajax缓存和HTTP缓存效果相同

现代浏览器的HTTP系统和缓存系统要比Ajax的XMLHttpRequest对象更靠近底层. 在这个层面上,浏览器并不知道或关心Ajax请求。它只是服从正常的基于从服务器返回的HTTP响应头缓存规则。

如果你已经知道HTTP缓存,您可以将这种知识应用到Ajax的缓存。唯一真正的区别是,您可能需要以不同的方式为静态文件设置响应头。

以下HTTP响应头是可以用来做Ajax缓存的:

  • Expires:应该被应用在你知道内容何时被修改的情况下。 例如,如果是股票价格您可能会设置一个在10秒后过期的数值。对于照片,你可以设置一个更长时间的Expires头,因为你指望它永远不改变。Expires头允许浏览器在一段时间内可以重复使用缓存内容,并避免任何不需要的同服务器的交互过程.
  • Last-Modified: 设置这个标记会通知浏览器可以使用If-Modified-Since头来产生一个条件GET请求以便检查其本地缓存。如果数据不需要更新,服务器将使用HTTP 304状态码来响应此请求
  • Cache-Control: 如果允许,这应该被设置为'public',使其他用户可以在中间代理和缓存服务器上存储和共享数据,在Firefox上,这还将启用针对HTTPS的缓存

当然,如果您使用Ajax的POST方法,这并不适用,因为POST请求不会被缓存。如果您的Ajax请求有安全性要求,你应该总是使用POST方法,例如:银行帐户的资金转账。

我们创建了一个Ajax缓存例子来展示这些响应头的效果. 使用HttpWatch, 你可以看到我们在ajax响应头里面设置了上述全部3个响应头:

Ajax 缓存头

如果你以固定频率多次点击'Ajax Update'按钮, 你会发现ajax大约每隔1分钟更新一次,因为Expires头设置为在未来的1分钟后过期。在HttpWatch截图里面你可以看到重复点击刷新按钮导致ajax请求直接从浏览器缓存里面读取,没有发生任务网络活动(即在发送和接收列里面字节数都为0) :

Ajax 缓存

最后一次点击发生在 1:06.531 ,因为缓存的数据已经超过1分钟,Ajax请求发生了一次网络通讯。从服务器返回的响应头200指明新的内容应该被重新下载。

事实2: IE浏览器不会刷新过期日期前的Ajax内容

有时,Ajax是用来在加载时填充网页的内容(如价格清单)。当页面加载完毕事件发生后,它直接被JavaScript调用,而不是依靠按一个按钮来触发。这使得Ajax调用表现为它好像是一个嵌入的资源

当你开发一个这样的网页时,通常的想法是试图通过更新嵌入的Ajax内容来刷新页面。对于其它嵌入的资源比如CSS或图片,浏览器自动发送的请求取决于F5 (刷新)或 Ctrl+F5 (强制刷新)

  1. F5(刷新) 如果原本的内容有一个Last-Modified 响应头,浏览器会建立一个有条件的更新请求. 浏览器使用If-Modified-Since 请求头使得服务器可以返回HTTP 304响应代码来避免不必要的下载。
  2. Ctrl+F5 (强制刷新) 导致浏览器发送一个没有条件的GET请求,其中Cache-Control请求头被设置为'no-cache'. 这代表不管浏览器需要的内容是否已经被缓存,所有的中间代理和缓存服务器都需要重新从原始服务器来下载此内容。

Firefox会将刷新类型传递给所有Ajax请求来刷新页面,因此任何Ajax派生的内容都会被更新。这个HttpWatch插件的屏幕快照显示了我们的Ajax缓存刷新 页面效果:

Firefox下刷新Ajax

Firefox 确保Ajax请求是被假定为带条件的GET。在我们这个例子页面内,如果缓存的数据在10秒以内,服务器会返回304代码,如果数据过期 ,服务器会返回200的代码.

在 Internet Explorer中, 已加载的Ajax请求被视为和页面刷新无关的内容,用户的刷新动作也不会被传递到Ajax中。如果缓存的Ajax内容还没过期,IE不会发生GET请求到服务器,它直接从缓存读取内容,导致在HttpWatch中看到(Cache)数据的产生。下面是在IE中缓存没有过期时按F5的效果:

IE刷新Ajax请求

即时按Ctrl+F5, Ajax仍然从缓存中加载内容:

IE 强制刷新

这意味这在IE中,即使你按强制刷新(Ctrl+F5),在内容过期之前,Ajax也不会更新。确保更新的唯一方法是从缓存中删除此记录。在HttpWatch中, 你可以通过使用下面的工具:

清空缓存

posted @ 2009-08-28 14:45 YSLOW 中文介绍 阅读(267) | 评论 (0)编辑

1. 精简JavaScript

为了减小JavaScript文件的大小,我们需要精简JavaScript,主要工作是去除多余的和不必要的字符,例如注释、行间缩进等。然而注释代码和行间缩进对于开发来说是不可缺少的关键环节,所以为了代码的可读性和易维护性,流行的解决方案是使用批处理脚本将开发环境中的文件进行精简并生成到开发环境内另一个文件夹或直接生成到生产环境下。

对于开发人员来说,精简代码并不需要对html页面进行任何修改,比较容易实现

网络上有很多精简代码的工具,例如JSMin( http://crockford.com/javascript/jsmin),shrinksafe( http://dojotoolkot.org/docs/shrinksafe)

2. 合并css JavaScript

从尽量减少HTTP请求的优化规则和实际产生的效果来看,合并css和js文件产生的性能提升要比精简和压缩代码要高很多。

然而,合并css和JavaScript文件对开发人员来说是个不小的挑战。

一种解决方案是直接合并css JavaScript文件

和精简JavaScript代码类似,使用批处理脚本将开发环境中的文件进行精简并合并到另一个指定的文件内,但这要求开发人员保证在html页面内引用css JavaScript文件时要直接引用合并后的文件,而且不同页面内需要引用不同数量的css JavaScript,不同版本的JavaScript存在版本控制,这就需要版本控制人员和项目管理人员的合作。

如果网站内JavaScript css数目比较少,更新不是很频繁,可采用此方案

采用此解决方案的优点是内容均是静态内容的分发,CDN站点支持静态内容即可。缺点是版本和内容控制比较复杂

另一种比较简单的解决方案是采用文件合并引擎

例如: 原html代码:

<script type="text/javascript"
src="http://yui.yahooapis.com/2.5.2/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script type="text/javascript"
src="http://yui.yahooapis.com/2.5.2/build/container/container_core-min.js"></script>
<script type="text/javascript"
src="http://yui.yahooapis.com/2.5.2/build/menu/menu-min.js"></script>
<script type="text/javascript"
src="http://yui.yahooapis.com/2.5.2/build/element/element-beta-min.js"></script>
<script type="text/javascript"
src="http://yui.yahooapis.com/2.5.2/build/button/button-min.js"></script>
<script type="text/javascript"
src="http://yui.yahooapis.com/2.5.2/build/editor/editor-beta-min.js"></script>

在一个没有cache缓存的机器上,此代码会产生6个http请求,而且此6个htt请求不能并发执行,导致加载变慢。

现在我们使用文件合并引擎,上述代码就可以写成以下形式

<script type="text/javascript"
src="http://yui.yahooapis.com/combo?2.5.2/build/yahoo-dom-event/yahoo-dom-event.js&
2.5.2/build/container/container_core-min.js&2.5.2/build/menu/menu-min.js&
2.5.2/build/element/element-beta-min.js&2.5.2/build/button/button-min.js&
2.5.2/build/editor/editor-beta-min.js"></script>

在一个没有cache缓存的机器上,此代码会仅产生1个http请求,虽然下载的总字节数没有变,但是将减少了浏览器和服务器之间的http请求次数,相应减少了http请求的通信量和http响应的通信量。

使用文件合并引擎需要开发人员自己开发此引擎,不过此类引擎比较容易实现。

缺点:现在使用CDN的大型网站越来越多,如果使用文件合并引擎,那么此CDN站点必须支持动态脚本内容,例如CGI或ASP或JSP等 或者采取一种折中的操作是将JavaScript和css内容单独分发到一个支持动态脚本的主机上。

在上面代码中http://yui.yahooapis.com/combo就是文件合并引擎,它将传入的6个文件名称在服务器上合并为一个文件并返回内容。

webwatch效果:

从http瀑布图来看,下载6个单独的js共需要190毫秒左右,而将6个js合并为一个需要30毫秒左右,耗时和一个单独的js文件差不多

posted @ 2009-06-23 11:59 YSLOW 中文介绍 阅读(248) | 评论 (0)编辑

英文原文地址

创建100个元素的时间

Iframes 提供了一个在页面中嵌入其它网站页面的简便方法,但应慎重使用。创建IFRAME比创建任 何其他类型的DOM元素(包括脚本和样式表)耗时多出1-2个数量级. 创建100个不同类型元素的时间展示了IFRAME多么的耗时.

页面通常不会使用太多数量的IFRAME,因此创建dom的时间也不是一个大问题,问题是这涉及到onload事件和并发连接池

Iframes 阻塞onload事件

尽快产生window的 onload事件是很重要的。这个事件会引发浏览器状态指示到达“完毕”状态,通知用户页面已经下载完毕。当onload事件被延迟,给用户的感受是页面变的更慢了

window的onload事件在所有的iframe和iframe内所有元素完全下载后才能触发。 在 Safari 和 Chrome浏览器内,通过JavaScript动态设置iframe的src属性可以避免这种阻塞行为

并发连接池

浏览器对任何一个给定的web服务器只打开一定数量的连接。 比较老的浏览器,包括Internet Explorer 6 7 、Firefox 2, 对一个域名默认仅打开2个连接。在新型浏览器内这个限 制被提高了,Safari 3+ 、Opera 9+ 对一个域名默认打开4个连接,Chrome 1+, IE 8, Firefox 3 对一个域名默认打开6个连接。 你可以查看下面这个表格并发连接汇总.

有人可能希望一个iframe有它自己单独的并发连接池,但是事实并不是这样。在所有主流浏览器中,连接池是被页面和iframe共享的。这意味着有可能一个iframe内的资源占据了所有 可用的连接并阻塞了主页面的资源下载。如果iframe内的内容和主页面一样重要或者更重要,这是没有问题的。但如果iframe不太重要,iframe占用连接是不可取的。一个解决办法是在 更高级别的资源下载之后,动态设置iframe的src属性动态加载内容

美国10大网站中5个使用了iframe。大多数情况下,它们常用来加载广告。这是不幸的,但可以理解,因为使用iframe插入广告内容很容易实现。在许多情况下,iframe是合乎逻辑的 解决方案。但要记住他们会对你的页面产生性能影响。尽可能避免使用iframe,当必须使用时,要有节制的使用它们

posted @ 2009-06-05 11:11 YSLOW 中文介绍 阅读(185) | 评论 (0)编辑