16 November 2014

前言

网站加速的一些规则,来源自yahoo的开发者网站的规则。算是他山之石,可以攻玉。原文地址: https://developer.yahoo.com/performance/rules.html,译文来自oschina: http://my.oschina.net/hmj/blog/27881,内容作部分修改。

经验丰富的性能团队已经发现了许多加速网页的最好实践做法。这个清单列出了35条最佳的实践,并划分为7类。

七个分类包括:内容(Content),服务器(Server),Cookie,样式表(CSS),Javascript, 图像(Images),移动设备(Mobile)

注: 目前我能作出处理和应对的是, Server、Cookie、Javascript以及部分的内容控制。

一、最小化HTTP请求(Minimize HTTP Requests)

标签:内容(content)

80%的终端用户的时间都花费在了前端(front-end)。大多数的这些时间都花在了下载页面中的所有组件上:图片,样式,脚本,flash,等等。减少组件的数量从而减少渲染页面的所必须的HTTP请求的数量。这是网页提速的关键所在。

一个减少页面中的页面组件的办法是简化页面的设计。但是有没有办法在用丰富的内容构建页面的同时,又能获得很快的响应时间呢? 下在这有些技术用来减少HTTP请求的数量,与此同时又支持富内容的设计。

组合文件(Combined files)是一种减少HTTP请求的方式,即通过将所有的脚本组合到单一的脚本文件中,同样的将所有的CSS样式组合到一个样式文件中。当脚本和样式在不同的页面中变化各异时,组合文件是十分富有挑战性的,但是在应用发布中使这种方式会提高响应时间。

备注: 这里的组合文件的方法也就是Rails中的Asset Pipeline所使用的方法,即使用某种编译器,将css和js压缩到一个文件中,并打上响应的标识码。

CSS精灵(CSS Sprites)是一种减少图像请求数量非常好的办法。将你的所有背景图像加入到同一张图片中,然后利用CSS的background-imagebackground-position属性来展现你想要的图像片段。

图片映射(Image maps)将所有的图片组合到单一图片文件,图片整体的大小基本是相同的,但是这减少了HTTP请求并且加快了页面速度。仅但页面中的图片是连续的,图片映射才会起作用,比如导航条。图片映射的坐标的定义可能是冗繁和易于出错的。导航中使用图片映射也是不可访问的,所以这种办法不推荐使用。

内联图片(inline imags)利用 data: URL scheme 在实际页面中嵌入图片数据。这可能会增加HTML文档的体积。将你的内联图片组合到样式表(可缓存的)中是一个既能减少HTTP请求,又能避免页面体积膨胀的办法。然而内联图片并不是所有主流浏览器都支持的。

减少页面中的HTTP请求的数量是起点。对于那些第一次访问页面的人来说,减少HTTP请求是提高其访问性能的最好的指导。正如在Tenni Theurer的博客Browser Cache Usage - Exposed!中所说的40%-60%的访问者会在没有缓存的情况下访问你的站点。对于这些初次访问者,用户体验的关键是提高页面加载速度。

二、使用内容发布网络

标签:服务器

用户和服务器的距离对响应时间影响巨大。在多个地理上分散的服务器部署内容,对用户而言,会使页面加载速度更快。但是如何下手呢?

对于实现地理上分布内容的第一步来说,不要试图将web应用重新设计为分布式架构。根据你的应用,改变架构云会导致令人生畏的任务,比如 多服务器之间session状态同步和复制数据库事务。尝试缩短用户和你的内容服务器的距离可能会被修改应用本身的架构所耽误。

记住80-90%的终端用户的响应时间都花费在了下载页面中的所有组件上了,包括:图像,样式表,脚本,flash等等。这是性能的黄金法则。与其十分困难的开始重新设计应用架构,倒不如分散你的静态内容(static content)。这不但获得了更短的响应时间,而且还因为分布网络而变得更加容易。

一个内容分布网(Content Delivery Network)CDN是一个跨多地点更加高效分发内容到用户的分布式web服务器的集合。分发内容到具体用户的服务器,通常是依据网络距离的测量来选择的。例如有更少网络跳数的服务器,或者响应时间最快的服务器会被选中。

一些大型的网络公司会拥有自己的CDN,但是使用CDN服务提供商提供的服务会划算,例如: Akamai Technologies, EdgeCast, 或者 level3。对于初创公司和私营站点来说,CDN服务的这部分花销可能会省略。但是随着用户的增长以及全球化,CDN对于获得更快的响应速度来说是十分必要的。在雅虎,将静态内容与应用所在的web服务器分隔并移动到 CDN上,缩短了20%或者更多的用户响应时间。转换到CDN是相当容易的代码更改,并且可能极其显著的提高站点响应速度。

三、添加一个 Expires 或者一个 Cache-Control 头部信息

内容:服务器

这条原则包括两方面:

  • 对于静态组件:通过设置相当遥远的Expires信息头,从而来实现 “Never expire”策略
  • 对于动态组件:使用合理的Cache-Control头,协助浏览器进行有选择性的请求。

Web页面的设计变得越来越丰富,这意味着页面中会出现更多的脚本,样式表,图片和flash。初次访问站点的用户可能不得不发送多次HTTP请求,但是通过使用Expires头,你可以使得这些组件成为可缓存的(Cacheable)。从而避免了随后页面中的不必要的请求。Expires头多数用于图片上,但是它应该被用在所有的组件上,包括脚本,样式表,以及Flash。

浏览器(和代理)里用缓存机制来减少之后页面展示中HTTP请求的数量和大小。Web服务器使用包含Expires头的响应来通知客户端一个组件可以被缓存多长时间。下面是一个Expires头信息,通知浏览器该响应内容直到2010年4月15日才会失效

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

如果你的服务器是Apache,使用ExpiresDefault 指令来设置一个相对当前时间的失效时间。如下的ExpiresDefault例子中,设置过期时间为10年。

ExpiresDefault "access plus 10 years"

记住:如果使用Expires,一旦组件发生变化,就必须要修改组件的文件名。在雅虎,将修改文件名设置成构建进程的一部分,在组件的文件名中嵌入版本号,例如: yahoo_2.0.6.js。

只有在一个用户访问过你的站点后,才能使用Expires头来影响页面的视图。对于初次访问你站点的用户,以及那些浏览器缓存为空用户,这个办法对于以上两种情况下发出的HTTP请求的数量是没有任何影响的。所以这条性能提升的影响取决于用户的”待发缓存(primed cache)”的命中率(待发缓存中已经包含了页面中的所有组件)。我们在雅虎上进行了测试,发现在75%-80%的页面带有待发缓存。通过利用Expires可以增加被浏览器缓存的组件数量,并且在之后的页面视图中,在没有通过用户网络连接发送任何一个字节的情况下,继续重用这些组件。

四、压缩组件

标签:服务器

前端工程师所作出的决定,能够显著的减少穿越网络传送HTTP请求和响应所花费的时间。事实上用户终端的带宽,互联网服务提供商,对等交换节点的距离等等已超出开发团队的控制范围。但是仍有其他的变量因子来影响响应时间。例如,通过压缩方式减少HTTP响应的大小,可以缩短响应时间。

从HTTP/1.1开始,web客户端就通过在HTTP请求的Accept-Encoding头显示的支持了压缩。

Accept-Encoding: gzip, deflate

如果web服务器遇到包含该字段( Accept-Encoding: gzip, deflate)的请求,它可能会使用客户端列出的方法之一来对响应进行压缩。web服务器通过在响应头中的 Content-Encoding 字段来告诉客户端已经对响应内容进行了压缩操作。

Content-Encoding: gzip

Gzip是当前最流行的和最有效的压缩方法。它是由GNU项目开发并被RFC1952标准化的。唯一其它你可能用到的压缩方式是deflate,但是它可能相对于Gzip,效率要低,知名度要低。

Gzip压缩通常会减少响应的大小的大约70%。今天通过浏览器传输的近乎90%的网络流量都宣称支持gzip。如果你是使用Apache,配置gzip的模块取决于你的Apache版本,Apache1.3使用mod_gzip,Apache 2.x使用mod_deflate

浏览器和代理中有一些被熟知的问题,可能在浏览器期望的东西和它实际收到的压缩内容之间引起一些错误。幸运的是,这些较为边缘的例子随着旧式浏览器的弃用而渐渐的被解决掉。Apache的模块通过自动添合适的不同的响应头信息来起作用。

服务器会根据文件类型来选择压缩的内容,但是可能在它所决定要压缩的内容上会受到限制。大多数的浏览器站点压缩他们的HTML文档。压缩你的脚本和样式表文件同样是值得,但是多数的站点会忽视这些。事实上,压缩任何的文本形式的响应都是值得的,包括XML和JSON。图像和PDF文件不应该再被压缩了,因为它们都已经是压缩形式的了。试图来压缩它们(图像和PDF)不但会浪费CPU,而且可能潜在的增加了文件的大小。

尽可能多的压缩文件(尤其是文本文件),是一种减轻网页重量和加速用户体验的较为简单的方式。

五、将样式文件放在顶部

标签:css

当研究雅虎的性能时,发现将样式文件放在文档HEAD标签中会使网页的下载速度加快。这是因为将样式表在HEAD标签中,浏览器会逐渐的渲染网页。

关注性能的前端工程师想要让网页来逐渐的加载;即想要浏览器来尽可能快的展现它所已经包含的一切内容。这对于包含许多内容的页面或者对于处在一个低速网络环境中的用户来说显得尤为重要。向用户展现诸如进度条的可视化反馈的重要性,已经被很好的研究和文档化。在我们的场景中,HTML页面就是进度的显示器。当浏览器逐渐的加载页面时,头部,导航条,顶部的logo,等等,所有的内容都会作为正在等待该页面的用户的可视化反馈。这提高了内在的用户体验。

将样式文件放在近乎文档的底部位置的问题: 会阻止了多数浏览器的逐步渲染过程,包括IE。这些浏览器会阻止渲染过程来避免当其中的样式改变时而不得不进行的页面元素的重塑。用户会被卡住,看到一个空白页面。

HTML的详细说明文档中很清楚的说明了样式应该被包含在页面HEAD标签中。不像A标签,LINK标签只能出现在文档的HEAD标签区域中。尽管他可能出现多次。不论是哪种备选方案,空白的屏幕,或者是无修饰内容的法拉盛,都不值得去冒险尝试!最佳的解决方案是遵从HTML详细说明书,把样式放在HEAD标签中。

六、将脚本放在底部

标签:Javascript

脚本引起的问题是他们阻塞了并发下载。 HTTP/1.1详细说明中建议浏览器在一个主机名中不要并发的下载超过两个组件。如果多个主机名下提供图片,可能出现超过多于两个的并发下载。但是当脚本被下载时,浏览器不会开启其它的下载,甚至是在不同的主机名下。

有些情况下将脚本移动到底部会不太容易。例如,加入你使用document.write来插入部分页面内容,这时便不能将其移到页面较低的部分。这可能会引起作用域问题。在多数情况下有许多办法来绕过这些问题。

经常被提及的一个可选的建议是使用延迟脚本。DEFER 属性标明了脚本中不包含document.write,并且指示浏览器可以继续渲染。不幸的是,Firefox不支持DEFER 属性。在IE中,脚本可以被延迟,但是不全是按预期的那样。如果一个脚本可以被延迟,它就能被移动到页面的底端。这会使你的页面加载更快。

备注: 在观察Yahoo!本身的页面源代码时,发现,其自生有一部分的javascript的引用放在HEAD(yui.js)中,而另一部分的js放在内容之下。上文中有介绍,包含document.write代码的放到底部不太适合。个人前些日子也做了相同的事情,感觉最大的问题是: 页面特定的js存在对js库的依赖的关系。

七、避免CSS表达式

标签:css

CSS表达式可能是一个强大的(危险的)方式来动态的设置CSS的属性。它们在IE5中开始被支持,但IE8不赞成其使用。举例,通过CSS表达式,可以每小时都轮流设置背景色:

background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" );

就像所展示的那样,expression方法接受一个Javascript表达式。CSS的属性值被设置为Javascript的表达式计算结果。expression方法在多数在其它浏览器中会被忽略,所以这对于在IE中设置创建跨浏览器的一致性体验的属性来说会有用。

表达式的问题是它们的计算频率会超乎多数人的预期的样子。不仅仅是当页面重新渲染和重设大小时它们会被计算,而且是当页面滚动甚至是用户在页面上移动鼠标时它们都会被计算。在CSS表达式上预设一个计数器允许我们追踪何时CSS表达式计算的时间和频率。在页面上移动鼠标可能很轻易产生超过10000次的计算。

减少CSS表达式计算次数的方法是使用one-time expressions,当表达式第一次执行时,where the first time the expression is evaluated it sets the style property to an explicit value, which replaces the CSS expression,如果样式属性在页面的整个生命周期中都要动态的设置,使用事件处理来代替css表达式是一个可选的方法。如果你必须要使用CSS表达式,记住它们可能被计算成千上百次并且会影响你页面的性能。

## 八、使Javascript和Css外部化

标签:Javascript,css

许多这些性能法则都是解决外部组件的管理方法问题。然而,在这些考虑出现前你应该问自己一个更加基础性的问题:Javascript和CSS是应该被包含在外部的文件中,还是应该嵌在页面本身中。

现实世界中使用外部文件总的来说都会产生更快的页面响应,因为Javascript和css文件在浏览器中是可缓存的。内联在HTML文档中的Javascript和CSS在HTML文档的每次请求中都被会下载。这减少了必要的HTTP请求的次数,但是却增大了HTML文档的大小。相反的,如果Javascript和CSS被包含在浏览器缓存的外部文件中,HTML文档的大小会被减小,HTTP的请求次数也没有增加。

之后,关键的因素是外部Javascript和CSS组件被缓存的频率,相对于请求的HTML文档的数量。这个因素,尽管很难定量,仍然可以通过多种度量方式来测量。如果你的站点用户在一次会话中有多个页面视图,并且你的许多页面都重用了相同的脚本和样式,这对于缓存的外部文件来说有很大的潜在益处。

Many web sites fall in the middle of these metrics. 对于这些站点来说,最好的解决方式是将Javascript和CSS作为外部文件进行部署。唯一例外的是,对于主页来说,内联方式是可选的最佳方式,例如 Yahoo!’s front page和My Yahoo!。在一次会话中有较少页面视图的主页可能会发现内联方式的Javascript和css会产生更快的终端用户响应时间。

对于是许多页面视图的第一前端页面来说,有许多折中技术来利用内联方式减少HTTP请求,同时兼得使用外部文件的缓存益处。其中的一个技术是在前端页面中内联Javascript和css,但是在页面文件加载完毕后动态的下载外部文件。之后的页面将引用浏览器中缓存的已存在的外部文件。

九、减少DNS查询

标签:内容

域名系统(DNS)建立主机名到IP地址的映射,就像电话簿映射人名到其电话号码一样。当你键入到你的浏览器(地址栏)中,浏览器所连接到的DNS解析器会返回服务器的IP地址。DNS也会有开销。DNS大概会花费20-120毫秒的时间为给定的主机名查询IP地址。浏览器不能从这个域名中下载任何东西,直到DNS查询完全结束。

DNS会缓存结果以为了更好性能。这个缓存可能存在于一个特殊的缓存服务器,该服务器由用户的ISP提供商或者局域网来维护,但是在用户的个人PC机中也会存在缓存的发生。DNS信息会保存在操作系统中的DNS缓存中(DNS Client Service on Microsoft Windows)。大多数的浏览器有自己的缓存,独立于操作系统中的缓存。只要浏览器在自己的缓存中保存DNS记录,就不会向操作系统发送记录请求了。

默认情况下IE将DNS查询结果缓存30分钟,这是在DnsCacheTimeout注册设置中规定的。Firefox会将DNS查询结果缓存1分钟,这可以通过network.dnsCacheExpiration配置进行控制。(Fasterfox 将时间改为1个小时)

当客户端的缓存是空白(对于浏览器缓存和操作系统缓存)时,DNS查询的(请求)数量等同于在web页面中包含的唯一主机名称的数量。这些包含网页URL,图片,脚本,样式表,Flash对象等等所用到的主机名称。减少唯一的主机名称会减少DNS的查询数量。

减少唯一主机名的数量,会潜在的减少网页中的并发下载数量。避免DNS查询缩短了响应时间,但是减少并发下载会增加响应时间。我的指导是将这些组件分隔在大于2个但小于4个的主机名称中。这会在减少DNS查询和允许一个较高并发下载之间达到一个较好的折衷。

## 十、缩减Javascript和CSS

标签:Javascript,css

缩减操作指的是移除代码中不必要的字符来缩小体积进而改善加载时间的操作。代码缩减后,所有的注释将被移除,不必要的空白字符(space, newline, and tab)将被移除。对于Javascript来说,这改善了响应时间效果,因为所下载的文件大小缩减了。两个比较流行的Javascript代码缩减工具是JSMinYUI Compressor,YUI Compressor同样也能缩减CSS代码。

除了可以减小外部的脚本和样式外,内联的

备注: 作为新一代的web框架,Rails中可以使用某种方式(turbo-sprockets-rails3)进行js和css压缩。

十一、避免重定向

标签:内容

重定向可以通过使用状态码301和302完成。以下是一个包含301的HTTP响应头的例子:

HTTP/1.1 301 Moved Permanently
Location: http://example.com/newuri
Content-Type: text/html

浏览器会自动将用户带到Location所指明的URL中去。所有重定向所需的信息都在头部。响应体通常是空的。不管它们的名字是什么,不论是301还是302响应,在实际中都不会被缓存,除了包含额外的头信息,例如Expires or Cache-Control,来指示它们将被缓存。meta标签的refresh和Javascript是其它可以将用户引向不同链接的方法,但是如果你必须要做一个重定向时,优先选择的技术是利用标准的3xx HTTP状态码,主要是保证后退按钮能正常工作。

主要要记住的是重定向会降低用户体验。在用户和HTML文档之间插入一个重定向,会延迟页面中的所有东西,因为页面中的任何东西都不会被渲染并且任何组件都不会被立即下载,直到HTML文档到来。

其中一个最浪费的重定向经常发生并且开发者们多数不会注意到它。它发生在一个在URL中本来应该存在的反斜杠(/)被丢失的情况下。例如:访问 http://astrology.yahoo.com/astrology导致一个包含301响应的重定向到http://astrology.yahoo.com/astrology/(请注意尾部增加的反斜杠)如果你使用Apache handler,这可以通过使用Alias或者mod_rewrite进行修复,或者用DirectorySlash 指令。

连接一个老的站点到一个新的站点是重定向的另一个比较普遍的用处。其它的用处是连接站点的不同部分或者基于特定条件(浏览器的类型,用户账户的类型,等等)来引导用户。使用重定向来连接两个站点是简单的并且只需要很少的额外代码。虽然在这些情况下利用重定向会减轻开发者的开发复杂度,但是却使用户体验降低了。如果你的两条代码路线都在同一台服务器上提供,那么可以使用Alias 和 mod_rewrite来替代以上方法。如果是域名变换引起的重定向,一个可选的办法是创建一个CNAME(一个DNS记录,用来创建一个别名从指向一个域名到另一个域名)来联合Alias 或者 mod_rewrite.

十二、删除重复的脚本

标签:Javascript

在一个页面中两次包含相同的脚本会影响性能。这不会像你想象的那样常见。一个对美国前十名网站的评审显示其中两个站点都包含了重复的脚本。在一个单文档中引发重复脚本机率增加的两个主要因素是:团队的大小和脚本的数量。当重复脚本的情况确实发生时,它会通过创建不必要的HTTP请求和浪费掉的Javascript的执行来影响性能。

不必要的HTTP请求发生在IE中,在Firefox中却不会发生。在IE中,如果一个外部的脚本文件被包含两次并且没有被缓存,在页面的加载过程中会产生两次的HTTP请求。尽管脚本是可缓存的,但是当用户重新加载页面时额外的HTTP请求又会产生。

除了产生浪费掉的HTTP请求外,时间也会由于多次解析脚本而被浪费掉。这些多余的脚本执行操作在IE和Firefox中都会存在,无论你的脚本是不是可缓存的。

一个解决偶尔发生的包含两次相同脚本的办法是在你的模板系统中实现脚本管理模块。典型的方式是在你的HTML页面中,在script标签包含你要使用的脚本。

<script type="text/javascript" src="menu_1.0.17.js"></script>

在PHP中的可选办法是创建一个叫做insertScript的函数。

<?php insertScript("menu.js") ?>

除了防止相同脚本在同一页面中插入多次,这个函数能处理其它的脚本问题,例如依赖检测和增加脚本文件名版本号来支持永恒的Expires 头。

十四、使Ajax可缓存

标签:内容

Ajax的显著好处之一是对于用户来说它提供了瞬间的反馈,因为它通过异步方式从后端服务器请求信息。然而,使用Ajax也不能保证用户不翘起拇指来等待这些异步返回的Javascript和XML。在许多站点中,用户是否要等待取决于Ajax的使用方式。例如,在一个基于web的邮件客户端中,用户会持续等待Ajax的请求结果来找到匹配其查询条件所有邮件信息。重要的是要记住”异步”并不代表”瞬间”。

为了提高性能,优化这些Ajax请求是很重要的。提高Ajax性能的最重要的方式是使响应可缓存的,正如在 Add an Expires或者a Cache-Control Header所说的那样。

一些其它的原则同样适用于Ajax:

  • Gzip Components
  • Reduce DNS Lookups
  • Minify JavaScript
  • Avoid Redirects
  • Configure ETags

让我们看一个例子,Web2.0的邮件客户端可能使用Ajax来下载用户的地址簿。如果在上次使用该web邮件应用时,用户没有编辑地址簿,之前的地址响应可以从缓存中被读出来,只要Ajax响应通过 Expires 或者 Cache-Control 头设置为可缓存的。相对于之前缓存过的地址簿,当用户要使用新的地址簿时,必须显示的通知浏览器。这可以通过在请求地址簿信息的Ajax的URL后加一个时间戳指示用户上次编辑地址簿的时间来完成。例如&t=1190241612。如果地址簿从上次下载后就没有编辑过,时间戳会是相同的并且地址簿会从浏览器缓存中读出,从而消除了额外的HTTP环回过程。如果用户已经编辑了他的地址簿,时间戳会保证新的URL不会匹配已经缓存的响应信息,之后浏览器会请求更新后的地址簿实体。

尽管在Ajax响应是动态创建的,并且只能被用于单一用户,它们仍旧可以被缓存。做这些会加速你的Web2.0应用。

Ajax的性能优化确实是个很重要的问题,想要大量应用Ajax,但是已经使用的Ajax又存在服务器端处理过于复杂的问题,响应速度过慢的问题。

十五、尽早清除缓存

标签:服务器

当用户请求一个页面时,服务器可能会花费200-500毫秒来组装HTML页面。在这段时间内,浏览器是处于空闲状态因为它在等待数据的到来。在PHP里存在flush()函数。它允许你发送部分已经准备好的HTML响应到浏览器中以便浏览器能够获取组件,而服务器此时正在忙于准备剩下的HTML页面。这些好处常被当称作是忙碌的后端或者是轻前端。

HEAD标签后被认为是是清除缓存的好的地方,因为HTML的head通常是容易准备的,并且允许浏览器并发下载HEADer中包含的任何CSS和Javascript文件,而此时后台仍旧忙于处理的过程中。

例子:

... <!-- css, js -->
    </head>
    <?php flush(); ?>
    <body>
... <!-- content -->

Yahoo! search 先前的研究和实际用户的测试证明了使用这项技术的好处。

十六、在AJAX请求中使用GET

标签:服务器

Yahoo! Mail的团队发现在使用XMLHttpRequest时,浏览器通过两步处理来实现POST方法:首先发送请求头,然后发送数据。所以最好使用GET方法,该方法只会发送一个TCP包(除非你有许多的cookies,GET能发送的数据存在大小限制)。IE中URL的最大长度是2K,所以如果你要发送超过2K的数据时你可能不能再用GET方法。

一个有趣的负面效果是不带有任何数据的POST方法的行为就像GET一样。基于HTTP详细说明书,GET方法是为了取回信息,所以当你真的只是请求数据时,使用GET是有有意义(语义上)的,相反的是发送数据到服务器端去存储是无意义(语义上)的。–这段话的意思,注意不要滥用GET请求。

十七、延迟加载组件

标签:内容

当你进一步观察你的页面时,你问自己:”在最初渲染页面时,到底什么是必须?”其它的内容和组件是可以等待的。

Javascript是理想的候选者,可以分散在加载事件之前或者之后。例如如果你有用于拖拽,拖放和动画的Javascript代码和库,这些都是可等待的,以为拖拽页面上的元素是在初始渲染之后才能实施的。其它可选的可延迟加载的内容包括隐藏内容(在用户动作之后才出现的内容)和折叠组件下的图片。

可以帮助你省事的工具: YUI Image Loader允许你延迟加载折叠组件下的图片,YUI Get utility 是联机加载Javascript和CSS的好方法。作为一个实例你可以在开启Firebug网络面板的情况下查看原生的Yahoo! Home Page来进行验证。

当性能目标和其它的最佳实践方式保持一致时是好的。在这种情况下,逐步增强的想法告诉我们,在支持的情况下,Javascript可以提高用户的体验但是你也必须保证在没有Javascript的情况下页面也能正常工作。所以在你确定页面已经正常工作之后,你可以通过延迟加载的脚本来给你添加更多的花样如拖拽,拖放和动画。

十八、预加载组件

标签:内容

预加载可能看起来与延迟加载是对立的,但实际上它是针对不同的目标的。通过预加载组件你可以充分利用浏览器的空闲时间来请求你不久将要的组件(如图片,样式,脚本)。这样当用户浏览下一个页面时,你可能已经缓存了多数的组件,对于用户来说你的页面将加载的更快。

以下有几种预加载的方式:

  • 无条件预加载 — 只要onload事件触发,你就会前去抓取额外的组件。例如检查google.com来了解一个精灵图片是如何在onload中被请求的。 google.com并不需要该精灵图片,但是在接下来连续不断的搜索结果页面中却是需要该图片的。
  • 有条件预加载 — 基于用户动作你会对用户接下来要去哪做一个有根据的猜测,从而进行相应的预加载。在search.yahoo.com你会发现在你在输入框中输入文字后, 一些额外的组件是如何被请求的。
  • 按期望的预加载 — 在再设计之前提前预加载。在再设计之后你经常会听到”新的站点很cool,但是比之前的站点要慢”。问题的一部分可能是 用户之前是在一个全缓存状态下浏览你的旧站点,但在空缓存状态下浏览你的新站点。你可以在重新加载新页面之前预加载其组件来缓解该副作用。 你的旧站点可以利用浏览器的空闲时间请求一些你的新站点会用到的一些图片,脚本。

十九、减少DOM元素的数量

标签:内容

复杂的页面意味着要下载更多的字节并且同样会降低Javascript访问DOM的速度。例如,一次通过500个DOM元素添加一个事件和一次通过5000元素添加一个事件处理,这之间是有很大差别的。

大量的DOM元素可能预示着在不去除必要内容的前提下,一些页面内容应该得到改善。你正在使用嵌套的表格作为布局用途吗?你正在加入更多的<div>标签而仅是为了修复布局问题吗?可能存在更好的且更加语义化的方式来处理你的标签。

YUI CSS utilities提供好的布局帮助:grid.css可以帮助你进行总体布局,font.css和reset.css可以帮助你去除浏览器的格式设置。重新开始考虑你的标签存在着挑战,例如只有在有语义时才使用<div>,而不是把它渲染为一个新行。

DOM的数量可以很容易的进行测试,只要在Firebug的console下键入:

document.getElementsByTagName('*').length

至于DOM的数量为多少时才能算多?检查一下类似的有较好标签设计的页面即可。例如 Yahoo! Home Page是一个复杂的页面但仍旧只有少于700个的HTML元素(HTML 标签)。

备注: 尝试了一下,公司主页中仅包含730个DOM元素,百度搜索中包含1038个。看来,DOM元素的数量并不是特别的多。

二十、跨域分隔组件

标签:内容

分隔组件让你能够最大化并行下载。确保你使用的域名不要超过2-4个,由于DNS查询也会有损耗。例如,提供HTML和动态的内容,并且在static1.example.org 和 static2.example.org之间分隔你的静态内容。

要获取更多的信息,查看由 Tenni Theurer 和 Patty Chi.发表的 “Maximizing Parallel Downloads in the Carpool Lane“。

二十一、减小iframes的数量

标签:内容

iframes允许HTML文档插入到它的父文档中。理解iframes的工作方式是十分重要的,只有这样我们才能更高效的利用iframes。




傲娇的使用Disqus