上海网站建设公司排名,如何卸载和重装wordpress,嘉兴seo推广优化,网站建设合同概念原文地址#xff1a;http://developer.yahoo.com/performance/rules.html 本文在尊重原文基础上#xff0c;尽量翻译得通俗易懂一些。 本文内容 提高 Web 站点性能的最佳实践最大限度减少 HTTP 请求 使用内容分发网络#xff08;CDN#xff09; 添加 Expires 或 Cache – C… 原文地址http://developer.yahoo.com/performance/rules.html 本文在尊重原文基础上尽量翻译得通俗易懂一些。 本文内容 提高 Web 站点性能的最佳实践最大限度减少 HTTP 请求 使用内容分发网络CDN 添加 Expires 或 Cache – Control 头 Gzip 组件 CSS 放在页面顶部 JavaScript 放在页面底部 避免 CSS 表达式 使用外部 JavaScript 和 CSS 减少 DNS 查询 精简 JavaScript 和 CSS 避免重定向 删除重复的脚本 配置 ETags 使得 Ajax 可缓存 尽早强制地发送缓冲给客户端 用 GET 发送 Ajax 请求 延迟加载组件 预加载组件 减少 DOM 元素数量 根据域名划分页面内容 最小化 iframe 数量 不要出现 404 错误 减小 Cookie 的大小 对组件使用无 coockie 域名 最小化 DOM 访问 开发智能的事件处理程序 用 link 代替 import 避免使用滤镜 优化图像 优化 CSS Sprites 不要在 HTML 中缩放图像 favicon.ico 要小且可缓存 保持组件 25K 以下 把组件打包到一个 Multipart 文档 避免图片 src 属性为空修改记录 下面是使页面更快的35个最佳实践它们被划分为7个类别。 类别: content、server、cookie、css、javascript、images、mobile Yahoo 开发的浏览器插件 YSLOW利用这七个类作为评价页面的指标 最大限度减少 HTTP 请求 类别: content 最终用户the end-user80的响应时间花费在前端the front-end。大部分时间用来下载页面中的所有组件图像、CSS、JS、Flash 等。因此反过来减少页面组件的数量就可以减少渲染呈现页面所需的 HTTP 请求的数量。这是加快页面的关键。 一个方法当然是简化页面设计减少页面组件的数量。但是否有方法既构建具有丰富内容的网页也实现了快速响应下面是减少 HTTP 请求数量的技巧也提供了丰富的网页设计。 合并文件。通过把所有脚本或 CSS 合并到一个单独的文件来减少 HTTP 请求的数量。当在不同的页面中脚本和 CSS 都不太一样时合并就比较困难。你可以把合并放到最后部署时从而改进响应时间。 CSS 精灵CSS Sprites。CSS Sprites是减少图像请求数量的首选方法。把你的背景图像合并到一个单独的图像并且使用CSS 的“background-image”和“background-position”属性来显示你所需的图像部分。 CSS Sprites 是一种 CSS 图像拼合技术一种网页图片应用处理方式。 图像地图Image maps。把多个图像合并到一个单独的图像。合并前与合并后的图像总体大小相同而且减少了HTTP请求的数量加快了页面速度。但只有当图像在页面中是连续的Image maps才好用如导航栏。定义图像地图的坐标很枯燥而且容易出错。对导航使用图像地图不具有可访问性所以不推荐。 内嵌图片Inline images。在页面中使用 data: URL scheme 嵌入图像数据。这会增加页面大小。Inline images 与 CSS已缓存相结合可以减少 HTTP 请求避免增加页面大小。目前所有主流浏览器尚不支持 Inline images。 减少页面的HTTP请求的数量首选要做的事对于改善用户初次访问页面的性能这是最重要准则。正如 Tenni Theurer 在其文章 Browser Cache Usage - Exposed! 指出的每天访问你网站的 40-60 人都是无缓存的都是初次访问无本地缓存。使页面对初次访问更快是更好的用户体验的关键。这些首次访问者的页面快速更好的用户体验是关键。 批注 一个页面往往包含很多资源比如图像、JS、CSS 等而这些资源都在服务器上客户端若想显示这个页面必须通过网络从服务器下载资源到本地。可想而知虽然每个资源都很小也就在几十 K 左右但是数量很多客户端每次需要这样资源都会到服务器上下载因此减少下载的次数或是下载完后直接从浏览器缓存里获得将很有意义。 本节的技巧合并文件、CSS Sprites、Image maps、Inline images 都是为了减少下载次数。比如如果一个页面需要三个 CSS那么在用户初次访问页面时需要向服务器请求三次。因此若将这三个 CSS 合并成一个那么只需下载一次图像也是如此一个页面最多的就是图像试想网站的导航条与其为每个操作都搞一个图片倒不如将这些图片合并在一个图像上再通过 CSS 获得图片局部区域。 使用内容分发网络CDN 类别: server 用户“接近”你Web服务器的程度会影响响应时间。把内容部署在多个、地理位置分散的服务器上会使页面加载的速度从用户角度看更快。但是我们应该从哪里开始 作为实现地理位置分散内容的第一步不要试图重新设计你的Web应用程序使它运行在一个分布式的结构中。根据应用程序改变结构包括跨服务器同步会话状态和复制数据库事务等这些艰巨的任务。根据不同的应用改变结构可以包括跨服务器的位置同步会话状态和复制数据库交易等艰巨任务。尝试减少用户和内容之间的距离可以延迟或从不通过这是应用程序结构的步骤。 记住最终用户的80-90 响应时间花费在下载所有页面的组件图像、CSS、JS、Flash 等这是提高性能的黄金法则。最好先分散你的静态内容如图像、CSS、JS、Flash 等而不是重新设计应用程序结构艰巨的工作开始。由于内容发布网络不仅大幅度减少了响应时间而且简化了应用程序。 一个 CDN 是一个处于多个位置的 Web 服务器的集合更有效地向用户发送内容。选择哪个服务器发送内容给特定用户通常是基于一个网络评估。例如选择最少的网络跳数或最快的响应时间。 一些大型的互联网公司拥有自己的 CDN而通过 CDN 服务提供商如 Akamai Technologies EdgeCast 或 level3成本则很高。对于刚成立的公司和私人站点一个 CDN 服务的成本可以让人望而却步但当你越来越受关注并全球化时一个 CDN 是必需的以便快速响应。以 Yahoo! 为例他们把静态内容从应用程序中移到 CDN上面提到 CDN 服务提供商以及他们自己的 CDN上提高了最终用户 20 以上的响应时间。使用 CDN 是一个只需要相对简单地修改代码显著改善站点速度的方法。 批注 客户端访问服务器要经过路由是要计算代价的最小跳数也好最少响应时间也罢所以将自己的网站内容部署在多个地理位置是有必要的。 添加 Expires 或 Cache – Control 头 类别: server 此规则有两个方面 对于静态组件设置 Expires 头为 Never expire 策略——“永不过期” 对于动态组件使用适当的 Cache – Control 头帮助浏览器有条件地发送请求。 随着页面越来越丰富这意味着更多的 JS、CSS、图像和 Flash。一个初次访问页面的用户会发出很多 HTTP 请求但是通过 Expires 头你可以使那些组件被浏览器缓存。在之后的页面浏览就避免了不必要的 HTTP 请求。Expires 头经常用在图像但也可以用在包括 JS、CSS 和 Flash 所有组件。 浏览器和代理使用缓存来减少 HTTP 请求的次数和规模使页面加载速度更快。一个 Web 服务器在 HTTP 响应中使用 Expires 头会告诉客户端这个组件被缓存多长时间。下面 Expires 头告诉浏览器这个响应直到 2011年4月15日 都是可靠的。 Expires: Thu, 15 Apr 2011 20:00:00 GMT 如果你的服务器是 Apache使用 ExpiresDefault 指令来设置相对于当前日期的过期时间。下面例子 ExpiresDefault 指令设置过期时间为发出请求后的 10年。 ExpiresDefault access plus 10 years 记住如果使用 Expires 头那么当组件改变时你必须改变组件的文件名。以 Yahoo 为例常常使这步作为生成过程的一部分一个版本号内置在组件文件名如 yahoo_2.0.6.js。 使用 Expires 头只影响那些用户已经浏览过的页面。当用户初次访问浏览器缓存为空时不会影响 HTTP 请求的数量。因此这种性能改善的影响取决于用户多长时间会在 primed cache primed cache 是已经包含页面中的所有组件它与 Empty Cache 相对命中你的页面。我们在 Yahoo 做了测试发现在 primed cache 浏览页面的频率是 75-85 。通过使用 Expires 头增加被浏览器缓存的组件数量在接下来的浏览中可以重用而无需通过用户的网络连接发送任何字节。 批注 根据 Yahoo 的统计用户从缓存中获得页面所有组件的频率在 75-85 那么我们很有必要告诉浏览器如何缓存页面资源。比如图像、CSS 这样的静态资源就告诉浏览器永不过期。而对动态资源则告诉浏览器要有条件的请求别重新请求。 Gzip 组件 类别: server 通过网络传输 HTTP 请求和响应所花费的时间可以通过前端机制而得到显著减少。事实上最终用户的宽带速度、Internet 服务器提供商、点对点交换接近程度等等因素不是开发团队能控制的但是还有其他影响响应时间的因素这些是可以控制的。压缩通过减小 HTTP 响应的大小来减少响应时间。 从 HTTP/1.1 开始Web 客户端用 HTTP 请求中的 Accept – Encoding 头来指示是否支持压缩。 Accept-Encoding: gzip, deflate 如果 Web 服务器在请求中看到这个头它可以利用客户端列出的方法之一压缩响应。Web服 务器通过响应的 Content – Encoding 头通知客户端。 Content-Encoding: gzip Gzip 是目前最流行和最有效的压缩方法。它是由 GNU 开发的项目并通过 RFC 1952 标准化。你可能看过其他压缩格式——deflate但它的效率较差不太流行。 Gzip 压缩一般可以减少约 70 的响应大小。目前大约有 90% 通过浏览器的互联网流量都声称支持Gzip今天的互联网流量约 90 穿过声称支持 gzip 的浏览器。如果你使用 Apache配置 Gzip 模块取决于你的版本Apache 1.3 使用 mod_gzip 而 Apache 2.x mod_deflate。 总所周知浏览器和代理带来的问题是可能会导致浏览器期望的与它收到的压缩内容不匹配。幸好这种特殊情况随着旧式浏览器使用的减少在减少。Apache 模块会自动添加变化的响应头来解决这个问题。 服务器选择什么压缩成 gzip要根据文件类型但通常很有限。大多数网站压缩他们的 HTML 文件脚本和 CSS 也很值得压缩但是很多站点错过了这个机会。事实上压缩任何文本响应包括 XML 和 JSON都是值得的。图像和 PDF 文件不应该被压缩因为它们已经被压缩了。试图压缩他们不仅浪费 CPU还会潜在增加文件的大小。 用 Gzip 压缩尽可能多的文件类型是一种减小页面大小加速用户体验的简单方法。 批注 如果你了解 HTTP 协议或是用相关网页测试工具那么一定知道服务器对客户端都响应了些什么。浏览器接收这些内容后解析并呈现给用户。无论是接收 CSS 、脚本文件还是图像那么服务器的响应的时候将它们压缩再发送给客户端就是很符合逻辑的结果。 CSS 放在页面顶部 类别css 在研究 Yahoo! 的性能时我们发现把 CSS 放到 HEAD 标记使得页面加载快了。这是因为把 CSS 放在 HEAD 标记使得页面逐渐地呈现。 关心性能的前端工程师期望一个页面能逐渐加载。也就是说我们希望浏览器尽快显示内容。这对于拥有较多内容的页面和网速较慢的用户来说特别重要。给用户返回可见的反馈的重要性比如进度指示已经做了很好的研究并形成了正式文档。在我们看来HTML 页面就是进度指示器。当浏览器逐渐加载页面头部、导航条、顶部 logo 等等对于等待页面加载的用户来说都可以作为可见的反馈信息。这便从整体上改善了用户体验。 把CSS放在接近文档底部的问题是阻止在很多浏览器上逐渐呈现包括 Internet Explorer。这些浏览器阻塞呈现是为了避免如果式样改变那么必须重绘页面元素。用户不得不面对一个空白页面。 HTML 规范清楚地指出 CSS 要包含在页面的 HEAD 区域“与 A 不同link /只能出现在文档的 HEAD 区域尽管它可以出现很多次。”无论是白屏还是出现没有式样的内容都是不值得的。最好的解决方法就是按照 HTML 规范在文档的 HEAD 里加载 CSS。 批注 有种情况你一定见过当很多人下载电影占了带宽网页要么打不开要么打开了有内容没式样。浏览器解析服务器发过来的页面总是有个顺序问题的。比如在没获得 CSS 文件前就准备呈现页面是没有意义的。 脚本放在页面底部 类别javascript 脚本带来的问题是它阻止了并行下载。HTTP/1.1 规范建议浏览器并行下载每个主机不能超过 2 个组件。如果你的图片放在多个主机上那么你可以从每个主机并行下载两个资源。然而当下载脚本时浏览器就不会下载其他资源即便资源位于不同的主机。 在某些情况下把脚本放在底部不太容易。比如如果脚本使用 document.write 向页面插入内容它就不能被往下移。这里还会有作用域问题。很多情况下都会遇到这方面问题。 一个经常用的方法是使用延迟脚本deferred scripts。DEFER 属性指示脚本不包含 document.write告诉浏览器可以继续呈现。不幸的是Firefox 并不支持 DEFER 属性。在 Internet Explorer 中脚本可以被延迟但效果可能不像期望的那样。如果脚本可以被延迟那么它就可以被移到页面的底部这将使页面加载加快。 批注 这点很容易理解。如果不考虑上面提到 document.write 情况那么绝大多数脚本要么是创建页面标记控件要么修改页面标记无论从那个角度讲脚本最后执行都是最合适的。 比如你在 HEAD 里的脚本使用了页面的元素那估计脚本会报错因为元素那时还没有被创建。所以CSS、JS 等页面资源别乱放。 现在的 Ajax 框架比如 jQuery 的 ready 方法Ext.Net 的 Ext.onReady 方法等都是处于这个目的。 避免 CSS 表达式 类别css CSS 表达式是动态设置 CSS 属性强大而危险的方法。从 Internet Explorer 5 开始支持 CSS 表达式但从 IE 8 开始被废弃。下面例子使用 CSS 表达式实现每隔一个小时设置一次背景颜色 background-color: expression( (new Date()).getHours()%2 ? #B8D4FF : #F08A00 ); 如上所示CSS 表达式使用了一个 JavaScript 表达式。CSS 属性根据 JavaScript 表达式的计算结果来设置。表达式在其它浏览器中不起作用因此在跨浏览器的设计中针对 Internet Explorer 设置属性会比较有用。 CSS 表达式的问题在于它的计算频率比我们想象得多。不仅在页面显示和缩放时也在页面滚动甚至在界面上移动鼠标都会重新计算。给 CSS 表达式增加一个计数器可以让我们跟踪表达式何时计算以及计算频率。随便在页面里移动鼠标都可以轻松达到 10000 次以上。 减少 CSS 表达式计算次数的一个方法是使用一次性的表达式。当第一次计算表达式时它将结果赋值给式样属性并用这个值代替 CSS 表达式。如果样式属性必须在页面周期内动态地改变那么一个可行的方法是使用事件处理而不是 CSS 表达式。如果你必须使用 CSS 表达式那么一定要记住它们可能要运行成千上万次有可能会影响以哦面性能。 批注 虽然有用但存在的问题很突出、更要命。所以还是不要使用的好。 使用外部 JavaScript 和 CSS 类别javascriptcss 很多性能规则都是如何管理外部文件但在你思考这些问题前你应该问一个更基本的问题JavaScript 和 CSS 是应该放在外部文件中还是应该内嵌在页面里 实际中使用外部文件通常可以提高页面速度因为JavaScript 和 CSS 文件可以被浏览器缓存。而内嵌在 HTML 文档中的 JavaScript 和 CSS 会在每次请求 HTML 文档时被重新下载。这虽然减少了所需的 HTTP 请求次数却增加了 HTML 文档的大小。而另一方面如果 JavaScript 和 CSS 在外部文件并被浏览器缓存那么在没有增加 HTTP 请求次数情况下减少 HTML 文档的大小。 然而关键问题是被缓存的外部 JavaScript 和 CSS 组件的频率与请求 HTML 文档的次数有关。尽管很难量化但还是有很多指标来测量它。如果用户在每次会话中浏览你网站的多个页面而这些页面重用了 脚本 和CSS那么使用可以被浏览器缓存的外部文件将会带来很大好处。 很多的网站没能建立起这些指标。对这些网站一般来说最好的解决方法是把 JavaScript 和 CSS 作为外部文件来部署。适合采用内嵌代码的唯一例外是网站的主页如 Yahoo!s front page 和 My Yahoo!。主页在每次会话中很少被浏览你会发现在主页嵌入 JavaScript 和 CSS 对最终用户的响应时间更快。 对于拥有较大访问量的首页有一种技术可以平衡嵌入代码带来的减少 HTTP 请求与使用外部文件带来缓存的好处。其中一个技术就是在首页中嵌入 JavaScript 和 CSS但完成加载后动态下载外部文件。接下来的页面就会使用已经被浏览器缓存的外部文件。 批注 既然只有外部文件才可以被浏览器缓存那么何乐不为呢。而且嵌入到页面脚本代码也不好维护同时会增大页面大小。 减少 DNS 查询 类别content 域名解析系统DNS提供域名和 IP 的映射就像电话本映射人名与他们的电话号码一样。当你在浏览器地址栏键入 www.dudo.org 时DNS 解析会返回给浏览器对应的 IP。DNS 解析是有时间代价的。一般情况下查找给定域名对应的 IP需要 20 到 120 毫秒。在这个过程中浏览器不会下载任何东西直到 DNS 查询完毕。 缓存 DNS 查询可以改善性能。DNS 缓存发生在要一个特定的缓存服务器由用户的 ISP 或本地网络维护但也会缓存在用户自己的机器上。DNS 信息保存在操作系统的 DNS 缓存中微软 Windows 操作系统的 DNS Client Service。大多数浏览器都有自己的缓存它独立于操作系统之外。只要浏览器在自己的缓存维护一个 DNS 信息在一次请求中就不会受到操作系统的影响。 默认情况下Internet Explorer 的 DNS 缓存为 30 分钟由注册表的 DnsCacheTimeout 规定。Firefox 的 DNS 缓存为 1 分钟由配置文件 network.dnsCacheExpiration 控制Fasterfox 为 1 小时。 当客户端的 DNS 缓存为空浏览器和操作系统的 DNS 缓存都为空DNS 查询的次数等于页面中主机的数量。这包括页面中的 URL、图像、JS、CSS、Flash 等使用的主机。减少唯一主机名的数量就可以减少 DNS 查询的次数。 但减少唯一主机名的数量潜在地减少了并行下载的数量。虽然避免 DNS 查询次数节省了响应时间但是减少并行下载却增加了响应时间。我的原则是把页面组件分割在 2 个到 4 个主机之间。这样就是在减少 DNS 查询次数与较高的并行下载之间获得了权衡。 批注 Yahoo 还真是任何一个环节都不放过。但是试想一下DNS 查询在 20-120 毫秒之间这个时间里相当于可以从服务器上下载 1-2 个几十k的资源也许是 CSS 文件也许是脚本文件也许是图片所以减少 DNS 查询还是很有必要的。 精简 JavaScript 和 CSS 类别javascriptcss “精简”是工程实践的结论从代码中去掉不必要的字符以减少文件大小从而节省加载时间。去掉代码的所有注释、空白字符包括空格、换行、tab。在 JavaScript 中这会提高响应时间因为减少了下载文件的大小。精简 JavaScript 代码最流行、最广泛的两个工具是 JSMin 和 YUI Compressor。YUI Compressor 还可用于精简 CSS。 “混淆”是另外一种可用于源代码优化的方法。该方法要比精简复杂一些并且混淆很可能产生 BUG。在对美国前 10 名的网站调查中发现“精简”可以缩小源代码 21% 的体积而“混淆”可以达到 25%。尽管“混淆”可以更大程度减少代码大小但精简 JavaScript 的风险更小。 除了精简外部 JavaScript 和 CSS内嵌的 script 和 style 代码块也可以应该精简。即使使用 Gzip 压缩过的 JavaScript 和 CSS“精简”文件仍然可以减少 5% 以上的大小。随着使用的 JavaScript 和 CSS 大小的增加精简代码将会获得更大的益处。 批注 无论是 JavaScript还是 CSS所有页面资源都是要从服务器下载的它们当然是越小越好。所以往往三方框架比如 jQuery 等都会提供脚本文件的正式版本精简过的如果你打开看一下密密麻麻一坨和它们的debug版本。 避免重定向 类别content “重定向”是通过 HTTP 状态码 301 和 302 完成的。下面是一个 301 响应的 HTTP 头 HTTP/1.1 301 Moved Permanently Location: http://example.com/newuri Content-Type: text/html 浏览器会自动地把用户定向到 Location 中指定的 URL。所有重定向需要的信息位于头中。响应的内容可以是空的。无论是 301 响应还是 302它们都不会被缓存除非增加一个额外的头选项如 Expires 或者 Cache-Control来指定可以被缓存。meta 标记和 JavaScript 是另一个实现重定向的方法但是如果你必须要跳转那最好的方法是使用标准的 3XX HTTP 状态码这主要是为了确保“后退”按钮可以正确地使用。 需要记住的主要事情是重定向会降低用户体验。在用户和 HTML 文档之间插入一个跳转会延迟页面中所有元素的呈现因为在 HTML 文件被加载前页面的任何东西都不会被呈现组件也不会被下载。 经常发生最浪费的重定向也经常被网页开发者忽略。那就是URL 缺少斜杠/可本应该有。例如访问 http://astrology.yahoo.com/astrology 会导致 301 响应代码的跳转连接应该是 http://astrology.yahoo.com/astrology/ 注意末尾的斜杠。在 Apache 中可以使用 Alias 或者 mod_rewrite或者 DirectorySlash 检测来避免。 另一个经常使用重定向的情况是把旧网站连接到新网站。其他情况如连接网站的不同部分或根据一定条件浏览器类型、用户帐号类型等来引导用户。使用重定向连接两个网站很简单只需要很少的代码。尽管该方法对开发者来说减少了复杂度但是缺降低了用户体验。一个可替代的方法是如果两者在同一台服务器上那么可以使用 Alias 和 mod_rewrite。如果是因为域名改变而使用重定向那么可以结合 Alias 或 mod_rewrite使用 CNAME创建从一个域名指向另外一个域名的 DNS 记录。 批注 这个是有切身体会的尤其是使用客户端重定向浏览器重定向时页面跳转的速度实在是有点慢。 删除重复脚本 类别javascript 在一个页面中引用同一个 JavaScript 文件两次会影响性能。这种情况可能并不常见。在对于美国前 10 名网站的调查中显示其中的两家存在重复引用脚本的情况。有两个主要因素增加一个页面中重复引用脚本的几率团队规模和脚本数量。当发生这种情况时重复引用脚本会创建不必要的 HTTP 请求以及延缓脚本执行从而损害性能。 这种不必要的 HTTP 请求发生在 Internet Explorer而不会在 Firefox。在 Internet Explorer 中如果包含引用一个外部脚本两次并且它还不可缓存那么在页面加载期间它会产生两次 HTTP 请求。即使脚本可被缓存当页面重新加载时也会产生额外的 HTTP 请求。 除了产生多余的 HTTP 请求多次检查脚本也会浪费时间。无论脚本是否可被缓存在 Internet Explorer 和 Firefox 中都会发生多余的脚本执行。 一个避免意外地引用同一个脚本两次的方法是在你的系统中开发脚本管理模块。在 HTML 页面中包含脚本的常见方法是使用 script 标记 script typetext/javascript srcmenu_1.0.17.js/script 而在 PHP 中通过创建名为 insertScript 方法 ?php insertScript(menu.js) ? 为了防止多次插入同一个脚本该方法可以解决其他脚本问题例如依赖检查为脚本文件名添加版本号以便使用 Expire 头。 配置 ETags 类别server “实体标记Entity tagsETags”是 Web 服务器和浏览器用于确定浏览器缓存中的组件与服务器的一个原始内容是否匹配的一种机制。“实体”就是“组件”图像、脚本、CSS 等。添加 ETags 会提供一种验证实体的机制这比最后修改日期 last-modified date 更加灵活。一个 ETags 是一个唯一标识一个特定版本组件的字符串。字符串必须用双引号括起来。服务器通过 ETag 响应头来指定组件的 ETag。 HTTP/1.1 200 OK Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT ETag: 10c24bc-4ab-457e1c1f Content-Length: 12195 之后如果浏览器要验证一个组件那么它会使用 If-None-Match 头把 ETag 回传诶服务器。如果 ETags 匹配那么会返回 304 HTTP 状态码减少了 12195 字节的响应。 GET /i/yahoo.gif HTTP/1.1 Host: us.yimg.com If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT If-None-Match: 10c24bc-4ab-457e1c1f HTTP/1.1 304 Not Modified ETags 的问题在于它们通常使用网站服务器的唯一的属性来构造。当浏览器从一台服务器上获得原始组件之后尝试验证另一台服务器上的组件时ETags 就不会匹配。这种情况在使用集群服务器来处理请求的 Web 站点上相当普遍。默认情况下Apache 和 IIS 都把数据嵌入入到 ETag 中这样能显著减少在多服务器情况下成功在一台服务器验证的几率。 Apache 1.3 和 2.x 的 ETag 格式是 inode-size-timestamp。即使一个给定的文件在多个服务器的相同目录且具有相同的大小、权限、时间戳等但它的 inode 仍然是不同的。. IIS 5.0 和 IIS 6.0 的 ETags 具有类似的问题。IIS 的 ETag 格式是 Filetimestamp:ChangeNumber。ChangeNumber 是一个计数器用来跟踪 IIS 配置的改变。不同的是ChangeNumber 在一个 Web 站点的所有 IIS 都是相同的。 对于完全相同的组件在不同的服务器上由 Apache 和 IIS 产生的 ETags 不同。如果 ETags 不匹配那么用户不会收到一个小而快的 304 响应而是会得到一个正常的 200 响应并下载全部内容。如果你的网站只在一台服务器上那不会有问题。但是如果你的网站架设在多个服务器并且使用 Apache或默认 ETag 配置的 IIS那么用户获得页面会相对较慢你的服务器负载较高带宽消耗较大代理不会有效地缓存你的内容。即使你的组件具有 Expires 头无论用户何时点击“重载”或者“刷新”都会发送一个有条件的 GET 请求。 如果你没有利用 ETag 提供的灵活验证模式那么最好把 ETag 删掉。Last-Modified 头是基于组件时间戳来验证。删掉 ETag 会在响应和接下来的请求中减少 HTTP 头的大小。Microsoft Support article 文档描述如何删掉 ETag。在 Apache 中只需要在配置文件中简单添加下面一行代码就可以 FileETag none 批注 这种为资源的生成唯一标识的做法很常见。如果文件有改动那么唯一标识一定不同。 使 Ajax 可缓存 类别content Ajax 被提到的一个好处是由于它从服务器异步请求信息能为用户提供即时反馈。然而使用 Ajax 并不能保证用户不用等待那些返回的异步 JavaScript 和 XML 响应。在很多应用中用户是否等待取决于如何使用 Ajax。例如在一个基于 Web 的 Email 客户端中用户必须等待 Ajax 请求的结果返回符合查找条件的邮件信息。很重要的一点“异步”并不意味着“即时”。 为了提高性能优化 Ajax 响应很重要。提高 Ajxa 性能的最重要的方法是使响应可缓存如“添加 Expires 和 Cache-Control 头”小节描述的。其他几条规则也适用于 Ajax Gzip 组件 减少 DNS 查询 减小 JavaScript 避免重定向 配置 ETags 让我们看一个例子一个 Web2.0 Email 客户端会使用 Ajax 自动下载该用户的地址簿。如果用户在上次使用 Email Web 应用程序后没有修改地址簿那么如果用 Expire 或者 Cacke-Control 头设置 Ajax 可缓存就可以直接从缓存中读取地址薄。必须告诉浏览器是使用缓存中的地址薄还是发送一个新的请求。这可以通过给地址薄的 Ajax URL 添加一个时间戳指示用户最后修改地址簿的时间例如t11900241612。如果地址薄在上次读取后没有被修改过那么时间戳不变从浏览器的缓存中读取地址簿以减少额外的 HTTP 请求。如果用户修改了地址薄那么时间戳会确保新的 URL 与缓存中的响应不匹配浏览器将请求新的地址簿。 即便你的 Ajxa 响应是动态生成的哪怕它只应用于一个用户那也应该把它们缓存起来。这样可以使你的 Web2.0 应用程序响应速度更快。 尽早强制地发送缓冲给客户端 类别server 当用户请求一个页面时无论如何后端都会花 200 到 500 毫秒以便组织 HTML 页面。期间浏览器会一直是空闲的直到数据到达。在 PHP 中你可以使用 flush() 方法它允许你把部分 HTML 响应发送给浏览器这样浏览器就可以开始获取组件同时后台处理 HTML 页面的剩余部分。这样做好处在后端繁忙而前端空闲时最明显。 考虑强制发送的一个最好的地方是 HEAD 后因为 HTML 头通常最容易生成让你可以包含任何 CSS 和 JavaScript 文件以便浏览器在开始并行下载的同时后端仍然在处理。 例子 ... !-- css, js -- /head ?php flush(); ? body ... !-- content -- Yahoo! search 率先进行了研究真实的用户测试表明了该技术的好处。 批注 不用等到全部内容都有了再发给客户端这期间用户都看不到。有的话就立刻发出去让页面“慢慢”呈现出来。 使用 GET 发送 Ajax 请求 类别server Yahoo!Mail 团队发现当使用 XMLHttpRequest 时浏览器中 POST 的实现是两步过程首先发送头然后才发送数据。这样使用 GET 最好因为它只发送一个 TCP 包除非你有很多 cookie。IE URL 的最大长度为 2K因此如果你要发送一个超过 2K 的数据那就不能使用 GET。 一个有趣的副作用是没有真正发送任何数据的 POST 的行为有点像 GET。根据 HTTP 规范GET 意味着“检索”数据因此当你只是查询数据时GET 更加有意义从语意上也是如此相反发送并在服务端保存数据时使用 POST。 延迟加载组件 类别content 你可以仔细看一下你的网页问问自己“哪些内容是页面初次呈现所必需的”。剩下的内容和组件可以稍后加载。 JavaScript 是一个理想的选择按照 onload 事件分成两部分之前和之后。例如如果你有用于完成拖拽效果的 JavaScript 和库那么它们可以稍后加载因为页面的拖拽元素是在页面初始呈现后才发生的。其他稍后加载的选择包括隐藏的内容这些内容是用户操作后才出现的以及处于折叠的图像。 帮你减轻该工作的工具YUI Image Loader 可以让你推迟加载折叠部分的图片。YUI Get utility 是包含 JS 和 CSS 的便捷方法。例如你可以用 Firebug 的 Net 选项卡看一下 Yahoo! Home Page。 当性能目标体现在 Web 开发的最佳实践时就会有很好的效果。这种情况下通过渐进增强progressive enhancement 的思想告诉我们在支持 JavaScript 的情况下JavaScript 可以改进用户体验但是必须确保页面没有JavaScript 也可以正常工作。因此在确保页面运行正常后用延迟加载脚本来增强页面比如拖拽和动画脚本。 批注 刚开始只加载最基本暂时不需要的组件就不用加载。遵循“渐进增强”原则。 预加载组件 类别content “预加载”和“延迟加载”看似相反但实际上“预加载”是为了实现另外一种目标。通过预加载你可以利用浏览器空闲的时间请求将来需要的组件如图像、CSS 和脚本。使用这种方法当用户要访问下一个页面时页面的大部分组件都已经在缓存中了这会打打改善用户加载页面的速度。 下面是几种“预加载”的方法 无条件的预加载只要触发 onload 事件你就直接获取额外的组件。以 Google.com 为例看一下合成的图像是如何在 onload 中加载的。合成中的图像在 google.com 主页并不需要但在一个“连续”的检索结果页面中是需要的。 有条件的预加载根据用户的操作你可以推测出用户接下来会做什么进行相应的预加载。在 search.yahoo.com 中你可以看到在你在文本框输入后如何请求额外的组件。 期望的预加载在重新设计前应先考虑预加载。当重新设计后你经常能听到“新的站点和不错但比之前慢了”。部分问题在于用户在完全缓存里访问你的之前的站点而新的站点一直是空的缓存。因此即便要重新设计你也要通过预加载减轻这种副作用。旧站点使用浏览器的空闲时间请求新站点使用的图像和脚本。 批注 最明显的情况是“翻转”效果。 减少 DOM 元素数量 类别content 一个复杂的页面意味下载更多的数据也就意味着 JavaScript 访问 DOM 会变慢。例如当你添加一个事件处理时遍历页面的 500 或 5000 个元素是不一样的。 大量的 DOM 元素是一个征兆它意味着可以使用页面标记而无需删除内容。你是否布局而采用内置表格是否仅仅为了自适应而使用很多 DIV也许有一个更好更符合语义的方法。 用 YUI CSS utilities 来布局很方便grids.css 可以帮你整体布局font.css 和 reset.css 可以帮助你移除浏览器默认的格式。这提供了一个重新审视和思考标记的机会例如只有当在语义上说得通时才使用div而不是因为它能呈现一个新行才使用。 DOM 元素数量很容易计算只需要在 Firebug 控制台内输入 document.getElementsByTagName(*).length 那么多少个 DOM 元素算多可以对比一下好的页面。比如 Yahoo! Home Page 是一个内容很多的页面但它只有 700 个元素HTML 标签。 批注 页面好看与页面复杂总是很矛盾。够炫的页面往往都很复杂元素很多元素很多的话JavaScript 访问起来就会变慢。 根据域名分割组件 类别content 分割组件可以使你最大限度地并行下载。由于 DNS 查找的影响确保你使用的域名在2到4个之间。例如你可以把 HTML 和动态内容放在 www.example.org 上而把分割的静态组件图片、脚本、CSS放在 statics1.example.org 和 statics.example.org。 你可以在 Tenni Theurer 和 Patty Chi 合写的文章 Maximizing Parallel Downloads in the Carpool Lane 找到更多相关信息。 批注 既然在 HTML 规范中规定资源是可以并行下载的那么我们当然可以将网站的资源分别存在不同的地方。 最小化 iframe 数量 类别content ifrmae 元素可以在父文档中插入一个新的 HTML 文档。了解 iframe 如何工作才能有效地使用它。 iframe 优点 帮助加载缓慢的三方部件和广告等 Security sandbox 并行下载脚本 iframe 缺点 即便加载是空的也有代价 会阻止页面加载 没有语意 不要出现 404 错误 类别content HTTP 请求很昂贵。因此发送一个 HTTP 请求却获得一个无用的响应如404 Not Found是完全没必要的它只会降低用户体验而不会有一点好处。 有些站点把 404 错误响应页面改为“你是不是要找***”这虽然改进了用户体验但却浪费了服务器资源像数据库等。最糟糕的情况是指向一个外部 JavaScript 链接返回 404 错误。首先这个下载会阻塞并行下载。其次浏览器会试图解析 404 响应的内容就像它是 JavaScript 代码尝试在里边查找有用的东西。 减小 Cookie 大小 类别cookie 使用 HTTP coockie 有很多原因比如认证authentication 和个性化。在 Web 服务器与浏览器之间通过 HTTP 头来交换 coockie 信息。尽可能维持 coockie 的大小以减少对用户响应时间的影响很重要。 有关更多信息可以查看 Tenni Theurer 和 Patty Chi 的文章 When the Cookie Crumbles。该文内容的研究包括 去掉不必要的 coockie 尽可能维持 coockie 的大小以减少对用户响应时间的影响 注意在适当域名级别上设置 coockie以便其他子域不会受到影响 适当设置的过期时间。删除 cookie 较早的过期时间或没有能改善用户的响应时间。 对组件使用无 coockie 域名 类别cookie 当浏览器请求一个静态图像并且随请求发送 coockie 时服务器并不会使用这些 coockie。因此毫无疑问它们coockie 只会产生网络流量。你应该确保请求静态组件时请求中不带 cookie。创建一个域把你所有的静态组件放在该子域。 如果你的域名是 ww.example.org那么你可以把静态组件放在 static.example.org 上。然而如果你已经在顶级域 example.org 设置了 coockie而不是在 www.example.org 上那么所有对 static.example.org 的请求都将包含 coockie。在这种情况下你可以购买一个新域名存放你的静态组件并让这个域名无 coockie。Yahoo! 使用的是 ymig.comYouTube 使用的是 ytimg.comAmazon 使用 images-anazon.com 等。 使用无 coockie 域名存放静态组件的另外一个好处是一些代理服务器可能会拒绝缓存带 coockie 请求的组件。相关建议是如果你想确定是用 example.org 作为你的主页还是 www.example.org那么你可以考虑 coockie 带来的影响。没有 www 的会把 coockie 设置到 *.example.org 的所有域这样你就别无选择了。因此出于性能的考虑最好使用 www 子域名并在它上设置 coockie。 最小化 DOM 访问 类别javascript 用 JavaScript 访问 DOM 元素比较慢因此为了更好响应页面你应该 缓存已经访问过的原始 离线更新完节点后再将它们添加到文档树中 避免使用 JavaScript 来自适应布局 有关更多信息请查看 Julien Lecomte 的文章 High Performance Ajax Applications。 开发智能事件处理程序 类别javascript 有时页面反应迟钝这是因为太多绑定到 DOM 树元素的事件处理并且被频繁执行。这就是为什么使用事件托管event delegation。如果你在一个 div 中有 10 个按钮那么你只需在 div 上绑定一个事件处理利用委托而不是为每个按钮。事件冒泡时你可以捕捉到该事件并判断出是哪个事件发出的。 你也不用为了操作 DOM 树而等待 onload 事件。通常你所需要就是访问DOM 树中可用的元素。你也不必等待所有图像都加载完毕。不用 onloadDOMContentLoaded 是可以考虑的事件但在所有浏览器都支持它之前你可使用 YUI Event 工具它有一个 onAvailable 方法。 有关更多信息参看 Julien Lecomte 的文章 High Performance Ajax Applications。 批注 换句话说通过事件委托我们可以为 10 个按钮只使用一个事件而不是 10 个按钮搞 10 个事件处理。比如增删改三个按钮可以用一个事件来弄事件触发时可以知道当前操作的是什么。 用 link 代替 import 类别css 前面的最佳实践提到CSS 应该放在页面顶部以便渐进呈现。 在 IE 中import 的行为相当于把 link 放在页面顶部因此最好不要使用它。 避免使用滤镜 类别css IE 独有的 AlphaImageLoader 滤镜旨在修复 7.0 以下版本的半透明真彩色 PNG 图像问题。该滤镜的问题是当图像正被下载时它会阻塞呈现并冻结浏览器。滤镜也会增加内存消耗并被应用到每个元素而不是每个图像因此滤镜的问题是多方面的。 最好的方法是避免完全使用 AlphaImageLoader而是使用 PNG8它能在 IE 中很好地工作。如果你确实需要使用 AlphaImageLoader那应该使用 hack_filter不会影响到 IE7 以上版本的用户。 优化图像 类别images 设计人员为页面创建图像后向 Web 服务器上传图像前你可以试着做以下几件事 检查 GIF 图像看下图像中的颜色数量是否与调色板一致。使用 imagemagick 可以很容易检查 identify -verbose image.gif 如果你发现图像中只用了 4 种颜色而调色板中是 256 色那么这张图片就改进的空间。 尝试把 GIF 格式转换成 PNG 格式看看是否节省了空间。多数情况下会。早先由于浏览器支持有限开发者不太愿意使用 PNG 格式但现在已经成为过去。唯一一个问题是真彩 PNG 格式的 alpha 通道半透明问题不过 GIF 也不是真彩的并且不支持任何半透明。因此GIF 能做到的调色板 PNGPNG8同样也能做到除了动画。下面一条简单的 imagemagick 命令可以把 GIF 安全地完全转换成 PNG convert image.gif image.png 在你所有的 PNG 图像上运行 pngcrush或者其它 PNG 优化工具。例如 pngcrush image.png -rem alla -reduce -brute result.png 在你所有的 JPEG 图像上运行 jpegtran。这个工具可以对 JPEG 中出现的锯齿等做无损操作同时它还可以用于优化和清除图像中的注释以及其它无用信息如 EXIF 信息 jpegtran -copy none -optimize -perfect src.jpg dest.jpg 优化 CSS Sprites 类别images 通常在 Sprite 中水平排列图像比垂直排列的文件要小。 在一个 Sprite 中合并结合相似的颜色会帮助你保持较低的色彩数理想状态是 256 色以适应一个 PNG8。 Be mobile-friendly并且不要在一个 Sprite 中的图像之间留下较大的空隙。这不会影响文件的大小但对于迫切需要解压缩图像到一个像素地图上的用户来说需要更少的的内存。100x100 的图像是1 万个像素而 1000X1000 是 100 个万像素。 不要在 HTML 中缩放图像 类别images 不要使用比你实际需要的大的图像。因为你可以设置长宽。如果你需要 img width100 height100 srcmycat.jpg altMy Cat / 那么你的图像mycat.jpg就应该是 100x100 像素而不是把一个 500x500 像素的图片缩小来用。 批注 使用多大的图像就做多大的图像。你可能见过往往一个内容会有不同像素大小的版本比如工具栏按钮图标同时做 16×16 像素和 32×32 像素的。 favicon.ico 要小且可缓存 类别images favicon.ico 是一个放在你服务器根位置的图像。这是个必需的邪恶因为即使你不关心它浏览器仍然会请求它因此最好不要用 404 响应。此外由于位于同一个服务器每次发送 Cookie 都会请求它。这个图像也会干扰下载队列例如在 IE 中当你在 onload 请求一个额外的组件时favicon 将在这些额外组件前被下载。 因此为了减轻 favicon.ico 弊端应确保 favicon 要小最好在 1K 以下。 设置你感觉合适的 Expires 头若你想改变它但你不能重新命名它。你可以把 Expires 头设置为未来几个月。你可以检查当前 favicon.ico 的最后修改日期以便做决定。 ImageMagick 可以帮助你创建小的 favicons网站图例。 批注 千万别忘了 favicon.ico。这是浏览器默认下载的资源。 保持组件 25K 以下 类别mobile 这个限制与一个事实有关iPhone 不能缓存操作 25K 大小的组件。注意这是未压缩的大小。这个小是很重要的因为单独 gzip 完全不够。 有关更多信息参考 Wayne Shea 和 Tenni Theurer 的文章 Performance Research, Part 5: iPhone Cacheability - Making it Stick。 把组件打包到一个 Multipart 文档 类别mobile 把组件打包到一个 multipart 文档很像一个带附件的email它能使你在一个 HTTP 请求中获取多个组件切记HTTP 请求很昂贵。当你使用这个技术时首先要确定用户代理是否支持iPhone 不支持。 避免图片 src 属性为空 类别server img src 属性为空的经常发生。它有两种形式 直接 HTML 标记创建 img src JavaScript 代码创建 var img new Image(); img.src ; 这两种形式效果相同浏览器会向服务器发出另一个请求。 Internet Explorer 向页面所在的目录发出一个请求。 Safari 和 Chrome 向实际页面自身发出一个请求。 Firefox 3 和更早版本的行为与 Safari 和 Chrome 相同但其 3.5 版本解决了这个问题[bug 444931]不再发送请求。 Opera 当遇到img src 属性为空时什么都不做。 为什么这个行为很糟 发送大量不期望的流量会使服务器瘫痪尤其是每天有百万浏览的页面。 浪费服务器的处理周期却产生一个永远不会被查看的页面。 可能会破坏用户数据。如果你通过 cookie或其他方式追踪请求中的状态那么会有损坏数据的可能性。即使图像请求没有返回图像浏览器也会读取和接收所有的头包括所有 cookies。当余下的响应被丢弃损害可能已经产生。 这种行为的根本原因是在浏览器中完成 URI 解析的方式。这种行为定义在 RFC 3986 - Uniform Resource Identifiers。当遇到一个空字符串时就作为 URI它被看作是一个相对的 URI并根据 5.2 节定义的算法解决。在 5.4 节 列出了空字符串的例子。Firefox、Safari 和 Chrome 都按规范正确解析字符串而 Internet Explorer 没有还遵循早期的规范 RFC 2396 - Uniform Resource Identifiers已由 RFC 3986 代替。因此技术上浏览器做了它们被期望做的事来解析相对 URI。空字符串显然是个意外。 HTML5 在 4.8.2 节添加一个关于标记的 src 属性的描述指示浏览器不要发出额外的请求 src 属性必须存在并且必须包含一个有效的 URL它引用一个非交互式的、可选的、可有动画的图像源不能是页面或脚本。如果元素的基 URI 与文档地址相同那么 src 属性必须不能为空。 庆幸的是之后的浏览器不会存在这个问题。而不幸的是没有对 script src 和 link href 的规定。可能还是有时间调整以确保浏览器执行此行为。 该规则得到 Yahoo!s JavaScript guru Nicolas C. Zakas 的支持。有关更多信息参考 Empty image src can destroy your site。 修改记录 第一次 2011-12-29