1.尽量减少 HTTP 请求

80%的终端用户响应时间都花在了前端上,其中大部分时间都在下载页面上的各种组件:图片,样式表,脚本,Flash 等等。减少组件数必然能够减少页面提交的 HTTP 请求数。这是让页面更快的关键。

减少页面组件数的一种方式是简化页面设计。但有没有一种方法可以在构建复杂的页面同时加快响应时间呢?嗯,确实有鱼和熊掌兼得的办法。

合并文件是通过把所有脚本放在一个文件中的方式来减少请求数的,当然,也可以合并所有的 CSS。如果各个页面的脚本和样式不一样的话,合并文件就是一项比较麻烦的工作了,但把这个作为站点发布过程的一部分确实可以提高响应时间。

CSS Sprites 是减少图片请求数量的首选方式。把背景图片都整合到一张图片中,然后用 CSS 的 background-image 和 background-position 属性来定位要显示的部分。

图像映射可以把多张图片合并成单张图片,总大小是一样的,但减少了请求数并加速了页面加载。图片映射只有在图像在页面中连续的时候才有用,比如导航条。给 image map 设置坐标的过程既无聊又容易出错,用 image map 来做导航也不容易,所以不推荐用这种方式。

行内图片(Base64 编码)用 data: URL 模式来把图片嵌入页面。这样会增加 HTML 文件的大小,把行内图片放在(缓存的)样式表中是个好办法,而且成功避免了页面变“重”。但目前主流浏览器并不能很好地支持行内图片。

减少页面的 HTTP 请求数是个起点,这是提升站点首次访问速度的重要指导原则。

2.减少 DNS 查找

域名系统建立了主机名和 IP 地址间的映射,就像电话簿上人名和号码的映射一样。当你在浏览器输入www.yahoo.com的时候,浏览器就会联系DNS解析器返回服务器的IP地址。DNS是有成本的,它需要20到120毫秒去查找给定主机名的IP地址。在DNS查找完成之前,浏览器无法从主机名下载任何东西。

DNS 查找被缓存起来更高效,由用户的 ISP(网络服务提供商)或者本地网络存在一个特殊的缓存服务器上,但还可以缓存在个人用户的计算机上。DNS 信息被保存在操作系统的 DNS cache(微软 Windows 上的”DNS 客户端服务”)里。大多数浏览器有独立于操作系统的自己的 cache。只要浏览器在自己的 cache 里还保留着这条记录,它就不会向操作系统查询 DNS。

IE 默认缓存 DNS 查找 30 分钟,写在 DnsCacheTimeout 注册表设置中。Firefox 缓存 1 分钟,可以用 network.dnsCacheExpiration 配置项设置。(Fasterfox 把缓存时间改成了 1 小时 P.S. Fasterfox 是 FF 的一个提速插件)

如果客户端的 DNS cache 是空的(包括浏览器的和操作系统的),DNS 查找数等于页面上不同的主机名数,包括页面 URL,图片,脚本文件,样式表,Flash 对象等等组件中的主机名,减少不同的主机名就可以减少 DNS 查找。

减少不同主机名的数量同时也减少了页面能够并行下载的组件数量,避免 DNS 查找削减了响应时间,而减少并行下载数量却增加了响应时间。我的原则是把组件分散在 2 到 4 个主机名下,这是同时减少 DNS 查找和允许高并发下载的折中方案。

3.避免重定向

重定向用 301 和 302 状态码,下面是一个有 301 状态码的 HTTP 头:

HTTP/1.1 301 Moved Permanently
Location: http://example.com/newuri
Content-Type: text/html
浏览器会自动跳转到 Location 域指明的 URL。重定向需要的所有信息都在 HTTP 头部,而响应体一般是空的。其实额外的 HTTP 头,比如 Expires 和 Cache-Control 也表示重定向。除此之外还有别的跳转方式:refresh 元标签和 JavaScript,但如果你必须得做重定向,最好用标准的 3xxHTTP 状态码,主要是为了让返回按钮能正常使用。

牢记重定向会拖慢用户体验,在用户和 HTML 文档之间插入重定向会延迟页面上的所有东西,页面无法渲染,组件也无法开始下载,直到 HTML 文档被送达浏览器。

有一种常见的极其浪费资源的重定向,而且 web 开发人员一般都意识不到这一点,就是 URL 尾部缺少一个斜线的时候。例如,跳转到http://astrology.yahoo.com/astrology会返回一个重定向到http://astrology.yahoo.com/astrology/的 301 响应(注意添在尾部的斜线)。在 Apache 中可以用 Alias,mod_rewrite 或者 DirectorySlash 指令来取消不必要的重定向。

重定向最常见的用途是把旧站点连接到新的站点,还可以连接同一站点的不同部分,针对用户的不同情况(浏览器类型,用户帐号类型等等)做一些处理。用重定向来连接两个网站是最简单的,只需要少量的额外代码。虽然在这些时候使用重定向减少了开发人员的开发复杂度,但降低了用户体验。一种替代方案是用 Alias 和 mod_rewrite,前提是两个代码路径都在相同的服务器上。如果是因为域名变化而使用了重定向,就可以创建一条 CNAME(创建一个指向另一个域名的 DNS 记录作为别名)结合 Alias 或者 mod_rewrite 指令。

4.让 Ajax 可缓存

Ajax 的一个好处是可以给用户提供即时反馈,因为它能够从后台服务器异步请求信息。然而,用了 Ajax 就无法保证用户在等待异步 JavaScript 和 XML 响应返回期间不会非常无聊。在很多应用程序中,用户能够一直等待取决于如何使用 Ajax。例如,在基于 web 的电子邮件客户端中,用户为了寻找符合他们搜索标准的邮件消息,将会保持对 Ajax 请求返回结果的关注。重要的是,要记得“异步”并不意味着“即时”。

要提高性能,优化这些 Ajax 响应至关重要。最重要的提高 Ajax 性能的方法就是让响应变得可缓存,就像在添上 Expires 或者 Cache-Control HTTP 头中讨论的一样。下面适用于 Ajax 的其它规则:

Gzip 组件
减少 DNS 查找
压缩 JavaScript
避免重定向
配置 ETags
我们一起看看例子,一个 Web 2.0 的电子邮件客户端用了 Ajax 来下载用户的通讯录,以便实现自动完成功能。如果用户从上一次使用之后再没有修改过她的通讯录,而且 Ajax 响应是可缓存的,有尚未过期的 Expires 或者 Cache-Control HTTP 头,那么之前的通讯录就可以从缓存中读出。必须通知浏览器,应该继续使用之前缓存的通讯录响应,还是去请求一个新的。可以通过给通讯录的 Ajax URL 里添加一个表明用户通讯录最后修改时间的时间戳来实现,例如&t=1190241612。如果通讯录从上一次下载之后再没有被修改过,时间戳不变,通讯录就将从浏览器缓存中直接读出,从而避免一次额外的 HTTP 往返消耗。如果用户已经修改了通讯录,时间戳也可以确保新的 URL 不会匹配缓存的响应,浏览器将请求新的通讯录条目。

即使 Ajax 响应是动态创建的,而且可能只适用于单用户,它们也可以被缓存,而这样会让你的 Web 2.0 应用更快。

5.延迟加载组件

可以凑近看看页面并问自己:什么才是一开始渲染页面所必须的?其余内容都可以等会儿。

JavaScript 是分隔 onload 事件之前和之后的一个理想选择。例如,如果有 JavaScript 代码和支持拖放以及动画的库,这些都可以先等会儿,因为拖放元素是在页面最初渲染之后的。其它可以延迟加载的部分包括隐藏内容(在某个交互动作之后才出现的内容)和折叠的图片。

工具可帮你减轻工作量:YUI Image Loader 可以延迟加载折叠的图片,还有 YUI Get utility 是一种引入 JS 和 CSS 的简单方法。Yahoo!主页就是一个例子,可以打开 Firebug 的网络面板仔细看看。

最好让性能目标符合其它 web 开发最佳实践,比如“渐进增强”。如果客户端支持 JavaScript,可以提高用户体验,但必须确保页面在不支持 JavaScript 时也能正常工作。所以,在确定页面运行正常之后,可以用一些延迟加载脚本增强它,以支持一些拖放和动画之类的华丽效果。

6.预加载组件

预加载可能看起来和延迟加载是相反的,但它其实有不同的目标。通过预加载组件可以充分利用浏览器空闲的时间来请求将来会用到的组件(图片,样式和脚本)。用户访问下一页的时候,大部分组件都已经在缓存里了,所以在用户看来页面会加载得更快。

实际应用中有以下几种预加载的类型:

无条件预加载——尽快开始加载,获取一些额外的组件。google.com 就是一个 sprite 图片预加载的好例子,这个 sprite 图片并不是 google.com 主页需要的,而是搜索结果页面上的内容。
条件性预加载——根据用户操作猜测用户将要跳转到哪里并据此预加载。在 search.yahoo.com 的输入框里键入内容后,可以看到那些额外组件是怎样请求加载的。
提前预加载——在推出新设计之前预加载。经常在重新设计之后会听到:“这个新网站不错,但比以前更慢了”,一部分原因是用户访问先前的页面都是有旧缓存的,但新的却是一种空缓存状态下的体验。可以通过在将要推出新设计之前预加载一些组件来减轻这种负面影响,老站可以利用浏览器空闲的时间来请求那些新站需要的图片和脚本。

7.减少 DOM 元素的数量

一个复杂的页面意味着要下载更多的字节,而且用 JavaScript 访问 DOM 也会更慢。举个例子,想要添加一个事件处理器的时候,循环遍历页面上的 500 个 DOM 元素和 5000 个 DOM 元素是有区别的。

大量的 DOM 元素是一种征兆——页面上有些内容无关的标记需要清理。正在用嵌套表格来布局吗?还是为了修复布局问题而添了一堆的

YUI CSS utilities 对布局有很大帮助:grids.css 针对整体布局,fonts.css 和 reset.css 可以用来去除浏览器的默认格式。这是个开始清理和思考标记的好机会,例如只在语义上有意义的时候使用

DOM 元素的数量很容易测试,只需要在 Firebug 的控制台里输入:

document.getElementsByTagName(‘*‘).length

那么多少 DOM 元素才算是太多呢?可以参考其它类似的标记良好的页面,例如 Yahoo!主页是一个相当繁忙的页面,但只有不到 700 个元素(HTML 标签)。

8.跨域分离组件

分离组件可以最大化并行下载,但要确保只用不超过 2-4 个域,因为存在 DNS 查找的代价。例如,可以把 HTML 和动态内容部署在www.example.org,而把静态组件分离到static1.example.org和static2.example.org。

9.尽量少用 iframe

用 iframe 可以把一个 HTML 文档插入到父文档里,重要的是明白 iframe 是如何工作的并高效地使用它。
引入缓慢的第三方内容,比如标志和广告
安全沙箱
并行下载脚本
代价高昂,即使是空白的 iframe
阻塞页面加载
非语义

10.杜绝 404

HTTP 请求代价高昂,完全没有必要用一个 HTTP 请求去获取一个无用的响应(比如 404 Not Found),只会拖慢用户体验而没有任何好处。

有些站点用的是有帮助的 404——“你的意思是 xxx?”,这样做有利于用户体验,,但也浪费了服务器资源(比如数据库等等)。最糟糕的是链接到的外部 JavaScript 有错误而且结果是 404。首先,这种下载将阻塞并行下载。其次,浏览器会试图解析 404 响应体,因为它是 JavaScript 代码,需要找出其中可用的部分。

css 部分

11.避免使用 CSS 表达式

用 CSS 表达式动态设置 CSS 属性,是一种强大又危险的方式。从 IE5 开始支持,但从 IE8 起就不推荐使用了。例如,可以用 CSS 表达式把背景颜色设置成按小时交替的:

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

12.选择舍弃@import

前面提到了一个最佳实践:为了实现逐步渲染,CSS 应该放在顶部。

在 IE 中用@import 与在底部用效果一样,所以最好不要用它。

13.避免使用滤镜

IE 专有的 AlphaImageLoader 滤镜可以用来修复 IE7 之前的版本中半透明 PNG 图片的问题。在图片加载过程中,这个滤镜会阻塞渲染,卡住浏览器,还会增加内存消耗而且是被应用到每个元素的,而不是每个图片,所以会存在一大堆问题。

最好的方法是干脆不要用 AlphaImageLoader,而优雅地降级到用在 IE 中支持性很好的 PNG8 图片来代替。如果非要用 AlphaImageLoader,应该用下划线 hack:_filter 来避免影响 IE7 及更高版本的用户。

14.把样式表放在顶部

在 Yahoo!研究性能的时候,我们发现把样式表放到文档的 HEAD 部分能让页面看起来加载地更快。这是因为把样式表放在 head 里能让页面逐步渲染。

关注性能的前端工程师想让页面逐步渲染。也就是说,我们想让浏览器尽快显示已有内容,这在页面上有一大堆内容或者用户网速很慢时显得尤为重要。给用户显示反馈(比如进度指标)的重要性已经被广泛研究过,并且被记录下来了。在我们的例子中,HTML 页面就是进度指标!当浏览器逐渐加载页面头部,导航条,顶部 logo 等等内容的时候,这些都被正在等待页面加载的用户当作反馈,能够提高整体用户体验。

js 部分

15.去除重复脚本

页面含有重复的脚本文件会影响性能,这可能和你想象的不一样。在对美国前 10 大 web 站点的评审中,发现只有 2 个站点含有重复脚本。两个主要原因增加了在单一页面中出现重复脚本的几率:团队大小和脚本数量。在这种情况下,重复脚本会创建不必要的 HTTP 请求,执行无用的 JavaScript 代码,而影响页面性能。

IE 会产生不必要的 HTTP 请求,而 Firefox 不会。在 IE 中,如果一个不可缓存的外部脚本被页面引入了两次,它会在页面加载时产生两个 HTTP 请求。即使脚本是可缓存的,在用户重新加载页面时也会产生额外的 HTTP 请求。

除了产生没有意义的 HTTP 请求之外,多次对脚本求值也会浪费时间。因为无论脚本是否可缓存,在 Firefox 和 IE 中都会执行冗余的 JavaScript 代码。

避免不小心把相同脚本引入两次的一种方法就是在模版系统中实现脚本管理模块。典型的脚本引入方法就是在 HTML 页面中用 SCRIPT 标签:

1

16.尽量减少 DOM 访问

用 JavaScript 访问 DOM 元素是很慢的,所以,为了让页面反应更迅速,应该:

缓存已访问过的元素的索引
先“离线”更新节点,再把它们添到 DOM 树上
避免用 JavaScript 修复布局问题

17.用智能的事件处理器

有时候感觉页面反映不够灵敏,是因为有太多频繁执行的事件处理器被添加到了 DOM 树的不同元素上,这就是推荐使用事件委托的原因。如果一个 div 里面有 10 个按钮,应该只给 div 容器添加一个事件处理器,而不是给每个按钮都添加一个。事件能够冒泡,所以可以捕获事件并得知哪个按钮是事件源。

18.把脚本放在底部

脚本会阻塞并行下载,HTTP/1.1 官方文档建议浏览器每个主机名下并行下载的组件数不要超过两个,如果图片来自多个主机名,并行下载的数量就可以超过两个。如果脚本正在下载,浏览器就不开始任何其它下载任务,即使是在不同主机名下的。

有时候,并不容易把脚本移动到底部。举个例子,如果脚本是用 document.write 插入到页面内容中的,就没办法再往下移了。还可能存在作用域问题,在多数情况下,这些问题都是可以解决的。

一个常见的建议是用推迟(deferred)脚本,有 DEFER 属性的脚本意味着不能含有 document.write,并且提示浏览器告诉他们可以继续渲染。不幸的是,Firefox 不支持 DEFER 属性。在 IE 中,脚本可能被推迟,但不尽如人意。如果脚本可以推迟,我们就可以把它放到页面底部,页面就可以更快地载入。

javascript, css

19.把 JavaScript 和 CSS 放到外面

很多性能原则都是关于如何管理外部组件的,然而,在这些顾虑出现之前你应该问一个更基础的问题:应该把 JavaScript 和 CSS 放到外部文件中还是直接写在页面里?

实际上,用外部文件可以让页面更快,因为 JavaScript 和 CSS 文件会被缓存在浏览器。HTML 文档中的行内 JavaScript 和 CSS 在每次请求该 HTML 文档的时候都会重新下载。这样做减少了所需的 HTTP 请求数,但增加了 HTML 文档的大小。另一方面,如果 JavaScript 和 CSS 在外部文件中,并且已经被浏览器缓存起来了,那么我们就成功地把 HTML 文档变小了,而且还没有增加 HTTP 请求数。

20.压缩 JavaScript 和 CSS

压缩具体来说就是从代码中去除不必要的字符以减少大小,从而提升加载速度。代码最小化就是去掉所有注释和不必要的空白字符(空格,换行和 tab)。在 JavaScript 中这样做能够提高响应性能,因为要下载的文件变小了。两个最常用的 JavaScript 代码压缩工具是 JSMin 和 YUI Compressor,YUI compressor 还可以压缩 CSS。

混淆是一种可选的源码优化措施,要比压缩更复杂,所以混淆过程也更容易产生 bug。在对美国前十的网站调查中,压缩可以缩小 21%,而混淆能缩小 25%。虽然混淆的缩小程度更高,但比压缩风险更大。

除了压缩外部脚本和样式,行内的

80%的终端用户响应时间都花在了前端上,其中大部分时间都在下载页面上的各种组件:图片,样式表,脚本,Flash 等等。减少组件数必然能够减少页面提交的 HTTP 请求数。这是让页面更快的关键。
减少页面组件数的一种方式是简化页面设计。但有没有一种方法可以在构建复杂的页面同时加快响应时间呢?嗯,确实有鱼和熊掌兼得的办法。
合并文件是通过把所有脚本放在一个文件中的方式来减少请求数的,当然,也可以合并所有的 CSS。如果各个页面的脚本和样式不一样的话,合并文件就是一项比较麻烦的工作了,但把这个作为站点发布过程的一部分确实可以提高响应时间。
CSS Sprites是减少图片请求数量的首选方式。把背景图片都整合到一张图片中,然后用 CSS 的 background-image 和 background-position 属性来定位要显示的部分。
图像映射可以把多张图片合并成单张图片,总大小是一样的,但减少了请求数并加速了页面加载。图片映射只有在图像在页面中连续的时候才有用,比如导航条。给 image map 设置坐标的过程既无聊又容易出错,用 image map 来做导航也不容易,所以不推荐用这种方式。
行内图片(Base64 编码)data:URL 模式来把图片嵌入页面。这样会增加 HTML 文件的大小,把行内图片放在(缓存的)样式表中是个好办法,而且成功避免了页面变“重”。但目前主流浏览器并不能很好地支持行内图片。
减少页面的 HTTP 请求数是个起点,这是提升站点首次访问速度的重要指导原则。

2.减少 DNS 查找

域名系统建立了主机名和 IP 地址间的映射,就像电话簿上人名和号码的映射一样。当你在浏览器输入www.yahoo.com的时候,浏览器就会联系DNS解析器返回服务器的IP地址。DNS是有成本的,它需要20到120毫秒去查找给定主机名的IP地址。在DNS查找完成之前,浏览器无法从主机名下载任何东西。
DNS 查找被缓存起来更高效,由用户的 ISP(网络服务提供商)或者本地网络存在一个特殊的缓存服务器上,但还可以缓存在个人用户的计算机上。DNS 信息被保存在操作系统的 DNS cache(微软 Windows 上的”DNS 客户端服务”)里。大多数浏览器有独立于操作系统的自己的 cache。只要浏览器在自己的 cache 里还保留着这条记录,它就不会向操作系统查询 DNS。
IE 默认缓存 DNS 查找 30 分钟,写在 DnsCacheTimeout 注册表设置中。Firefox 缓存 1 分钟,可以用 network.dnsCacheExpiration 配置项设置。(Fasterfox 把缓存时间改成了 1 小时 P.S. Fasterfox 是 FF 的一个提速插件)
如果客户端的 DNS cache 是空的(包括浏览器的和操作系统的),DNS 查找数等于页面上不同的主机名数,包括页面 URL,图片,脚本文件,样式表,Flash 对象等等组件中的主机名,减少不同的主机名就可以减少 DNS 查找。
减少不同主机名的数量同时也减少了页面能够并行下载的组件数量,避免 DNS 查找削减了响应时间,而减少并行下载数量却增加了响应时间。我的原则是把组件分散在 2 到 4 个主机名下,这是同时减少 DNS 查找和允许高并发下载的折中方案。

3.避免重定向

重定向用 301 和 302 状态码,下面是一个有 301 状态码的 HTTP 头:
HTTP/1.1 301 Moved Permanently
Location: http://example.com/newuri
Content-Type: text/html
浏览器会自动跳转到 Location 域指明的 URL。重定向需要的所有信息都在 HTTP 头部,而响应体一般是空的。其实额外的 HTTP 头,比如 Expires 和 Cache-Control 也表示重定向。除此之外还有别的跳转方式:refresh 元标签和 JavaScript,但如果你必须得做重定向,最好用标准的 3xxHTTP 状态码,主要是为了让返回按钮能正常使用。
牢记重定向会拖慢用户体验,在用户和 HTML 文档之间插入重定向会延迟页面上的所有东西,页面无法渲染,组件也无法开始下载,直到 HTML 文档被送达浏览器。
有一种常见的极其浪费资源的重定向,而且 web 开发人员一般都意识不到这一点,就是 URL 尾部缺少一个斜线的时候。例如,跳转到http://astrology.yahoo.com/astrology会返回一个重定向到http://astrology.yahoo.com/astrology/的 301 响应(注意添在尾部的斜线)。在 Apache 中可以用 Alias,mod_rewrite 或者 DirectorySlash 指令来取消不必要的重定向。
重定向最常见的用途是把旧站点连接到新的站点,还可以连接同一站点的不同部分,针对用户的不同情况(浏览器类型,用户帐号类型等等)做一些处理。用重定向来连接两个网站是最简单的,只需要少量的额外代码。虽然在这些时候使用重定向减少了开发人员的开发复杂度,但降低了用户体验。一种替代方案是用 Alias 和 mod_rewrite,前提是两个代码路径都在相同的服务器上。如果是因为域名变化而使用了重定向,就可以创建一条 CNAME(创建一个指向另一个域名的 DNS 记录作为别名)结合 Alias 或者 mod_rewrite 指令。

4.让 Ajax 可缓存

Ajax 的一个好处是可以给用户提供即时反馈,因为它能够从后台服务器异步请求信息。然而,用了 Ajax 就无法保证用户在等待异步 JavaScript 和 XML 响应返回期间不会非常无聊。在很多应用程序中,用户能够一直等待取决于如何使用 Ajax。例如,在基于 web 的电子邮件客户端中,用户为了寻找符合他们搜索标准的邮件消息,将会保持对 Ajax 请求返回结果的关注。重要的是,要记得“异步”并不意味着“即时”。
要提高性能,优化这些 Ajax 响应至关重要。最重要的提高 Ajax 性能的方法就是让响应变得可缓存,就像在添上 Expires 或者 Cache-Control HTTP 头中讨论的一样。下面适用于 Ajax 的其它规则:

我们一起看看例子,一个 Web 2.0 的电子邮件客户端用了 Ajax 来下载用户的通讯录,以便实现自动完成功能。如果用户从上一次使用之后再没有修改过她的通讯录,而且 Ajax 响应是可缓存的,有尚未过期的 Expires 或者 Cache-Control HTTP 头,那么之前的通讯录就可以从缓存中读出。必须通知浏览器,应该继续使用之前缓存的通讯录响应,还是去请求一个新的。可以通过给通讯录的 Ajax URL 里添加一个表明用户通讯录最后修改时间的时间戳来实现,例如&t=1190241612。如果通讯录从上一次下载之后再没有被修改过,时间戳不变,通讯录就将从浏览器缓存中直接读出,从而避免一次额外的 HTTP 往返消耗。如果用户已经修改了通讯录,时间戳也可以确保新的 URL 不会匹配缓存的响应,浏览器将请求新的通讯录条目。
即使 Ajax 响应是动态创建的,而且可能只适用于单用户,它们也可以被缓存,而这样会让你的 Web 2.0 应用更快。

5.延迟加载组件

可以凑近看看页面并问自己:什么才是一开始渲染页面所必须的?其余内容都可以等会儿。
JavaScript 是分隔 onload 事件之前和之后的一个理想选择。例如,如果有 JavaScript 代码和支持拖放以及动画的库,这些都可以先等会儿,因为拖放元素是在页面最初渲染之后的。其它可以延迟加载的部分包括隐藏内容(在某个交互动作之后才出现的内容)和折叠的图片。
工具可帮你减轻工作量:YUI Image Loader可以延迟加载折叠的图片,还有YUI Get utility是一种引入 JS 和 CSS 的简单方法。Yahoo!主页就是一个例子,可以打开 Firebug 的网络面板仔细看看。
最好让性能目标符合其它 web 开发最佳实践,比如“渐进增强”。如果客户端支持 JavaScript,可以提高用户体验,但必须确保页面在不支持 JavaScript 时也能正常工作。所以,在确定页面运行正常之后,可以用一些延迟加载脚本增强它,以支持一些拖放和动画之类的华丽效果。

6.预加载组件

预加载可能看起来和延迟加载是相反的,但它其实有不同的目标。通过预加载组件可以充分利用浏览器空闲的时间来请求将来会用到的组件(图片,样式和脚本)。用户访问下一页的时候,大部分组件都已经在缓存里了,所以在用户看来页面会加载得更快。
实际应用中有以下几种预加载的类型:

  • 无条件预加载——尽快开始加载,获取一些额外的组件。google.com 就是一个 sprite 图片预加载的好例子,这个 sprite 图片并不是 google.com 主页需要的,而是搜索结果页面上的内容。
  • 条件性预加载——根据用户操作猜测用户将要跳转到哪里并据此预加载。在search.yahoo.com的输入框里键入内容后,可以看到那些额外组件是怎样请求加载的。
  • 提前预加载——在推出新设计之前预加载。经常在重新设计之后会听到:“这个新网站不错,但比以前更慢了”,一部分原因是用户访问先前的页面都是有旧缓存的,但新的却是一种空缓存状态下的体验。可以通过在将要推出新设计之前预加载一些组件来减轻这种负面影响,老站可以利用浏览器空闲的时间来请求那些新站需要的图片和脚本。

7.减少 DOM 元素的数量

一个复杂的页面意味着要下载更多的字节,而且用 JavaScript 访问 DOM 也会更慢。举个例子,想要添加一个事件处理器的时候,循环遍历页面上的 500 个 DOM 元素和 5000 个 DOM 元素是有区别的。
大量的 DOM 元素是一种征兆——页面上有些内容无关的标记需要清理。正在用嵌套表格来布局吗?还是为了修复布局问题而添了一堆的

s?或许应该用更好的语义化标记。
YUI CSS utilities对布局有很大帮助:grids.css 针对整体布局,fonts.css 和 reset.css 可以用来去除浏览器的默认格式。这是个开始清理和思考标记的好机会,例如只在语义上有意义的时候使用
,而不是因为它能够渲染一个新行。
DOM 元素的数量很容易测试,只需要在 Firebug 的控制台里输入:

document.getElementsByTagName(‘*‘).length

那么多少 DOM 元素才算是太多呢?可以参考其它类似的标记良好的页面,例如Yahoo!主页是一个相当繁忙的页面,但只有不到 700 个元素(HTML 标签)。

8.跨域分离组件

分离组件可以最大化并行下载,但要确保只用不超过 2-4 个域,因为存在 DNS 查找的代价。例如,可以把 HTML 和动态内容部署在www.example.org,而把静态组件分离到static1.example.org和static2.example.org。

9.尽量少用 iframe

用 iframe 可以把一个 HTML 文档插入到父文档里,重要的是明白 iframe 是如何工作的并高效地使用它。