性能测试网站www.webpagetest.org
1.尽量减少HTTP请求数
- 文件合并,减少资源请求次数
- CSS Sprites,合并背景图片
- 行内图片(base64)
2.减少DNS查找
减少不同主机名的数量同时也减少了页面能够并行下载的组件数量,避免DNS查找削减了响应时间,而减少并行下载数量却增加了响应时间。我的原则是把组件分散在2到4个主机名下,这是同时减少DNS查找和允许高并发下载的折中方案。
3.避免重定向
有一种常见的极其浪费资源的重定向,而且web开发人员一般都意识不到这一点,就是URL尾部缺少一个斜线的时候。例如,跳转到http://astrology.yahoo.com/astrology会返回一个重定向到http://astrology.yahoo.com/astrology/的301响应(注意添在尾部的斜线)。在Apache中可以用Alias
,mod_rewrite
或者DirectorySlash
指令来取消不必要的重定向。
4.让Ajax可缓存
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元素是一种征兆——页面上有些内容无关的标记需要清理。正在用嵌套表格来布局吗?还是为了修复布局问题而添了一堆的<div>
s?或许应该用更好的语义化标记。
YUI CSS utilities对布局有很大帮助:grids.css针对整体布局,fonts.css和reset.css可以用来去除浏览器的默认格式。这是个开始清理和思考标记的好机会,例如只在语义上有意义的时候使用<div>
,而不是因为它能够渲染一个新行。
DOM元素的数量很容易测试,只需要在Firebug的控制台里输入:
<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">document.getElementsByTagName('*').length</pre>
那么多少DOM元素才算是太多呢?可以参考其它类似的标记良好的页面,例如Yahoo!主页是一个相当繁忙的页面,但只有不到700个元素(HTML标签)。
8.跨域分离组件
分离组件可以最大化并行下载,但要确保只用不超过2-4个域,因为存在DNS查找的代价。例如,可以把HTML和动态内容部署在www.example.org,而把静态组件分离到static1.example.org和static2.example.org。
9.尽量少用iframe
10.杜绝404
11.避免使用CSS表达式
12.选择<link>舍弃@import
13.避免使用滤镜
IE专有的AlphaImageLoader滤镜可以用来修复IE7之前的版本中半透明PNG图片的问题。在图片加载过程中,这个滤镜会阻塞渲染,卡住浏览器,还会增加内存消耗而且是被应用到每个元素的,而不是每个图片,所以会存在一大堆问题。
最好的方法是干脆不要用AlphaImageLoader,而优雅地降级到用在IE中支持性很好的PNG8图片来代替。如果非要用AlphaImageLoader,应该用下划线hack:_filter来避免影响IE7及更高版本的用户。
14.把样式表放在顶部
脚本篇
15.去除重复脚本
16.尽量减少DOM访问
用JavaScript访问DOM元素是很慢的,所以,为了让页面反应更迅速,应该:
缓存已访问过的元素的索引
先“离线”更新节点,再把它们添到DOM树上
避免用JavaScript修复布局问题
17.用智能的事件处理器
有时候感觉页面反映不够灵敏,是因为有太多频繁执行的事件处理器被添加到了DOM树的不同元素上,这就是推荐使用事件委托的原因。如果一个div里面有10个按钮,应该只给div容器添加一个事件处理器,而不是给每个按钮都添加一个。事件能够冒泡,所以可以捕获事件并得知哪个按钮是事件源。
18.把脚本放在底部
脚本会阻塞并行下载,HTTP/1.1官方文档建议浏览器每个主机名下并行下载的组件数不要超过两个,如果图片来自多个主机名,并行下载的数量就可以超过两个。如果脚本正在下载,浏览器就不开始任何其它下载任务,即使是在不同主机名下的。
有时候,并不容易把脚本移动到底部。举个例子,如果脚本是用document.write插入到页面内容中的,就没办法再往下移了。还可能存在作用域问题,在多数情况下,这些问题都是可以解决的。
一个常见的建议是用推迟(deferred)脚本,有DEFER属性的脚本意味着不能含有document.write,并且提示浏览器告诉他们可以继续渲染。不幸的是,Firefox不支持DEFER属性。在IE中,脚本可能被推迟,但不尽如人意。如果脚本可以推迟,我们就可以把它放到页面底部,页面就可以更快地载入。
19.把JavaScript和CSS放到外面
很多性能原则都是关于如何管理外部组件的,然而,在这些顾虑出现之前你应该问一个更基础的问题:应该把JavaScript和CSS放到外部文件中还是直接写在页面里?
实际上,用外部文件可以让页面更快,因为JavaScript和CSS文件会被缓存在浏览器。HTML文档中的行内JavaScript和CSS在每次请求该HTML文档的时候都会重新下载。这样做减少了所需的HTTP请求数,但增加了HTML文档的大小。另一方面,如果JavaScript和CSS在外部文件中,并且已经被浏览器缓存起来了,那么我们就成功地把HTML文档变小了,而且还没有增加HTTP请求数
20.压缩JavaScript和CSS
21.优化图片
22.优化CSS Sprite
23.不要用HTML缩放图片
不要因为在HTML中可以设置宽高而使用本不需要的大图。如果需要
1
<img width="100" height="100" src="mycat.jpg" alt="My Cat" />
那么图片本身(mycat.jpg)应该是100x100px的,而不是去缩小500x500px的图片。
24.用小的可缓存的favicon.ico
25.给Cookie减肥
26.把组件放在不含cookie的域下
当浏览器发送对静态图像的请求时,cookie也会一起发送,而服务器根本不需要这些cookie。所以它们只会造成没有意义的网络通信量,应该确保对静态组件的请求不含cookie。可以创建一个子域,把所有的静态组件都部署在那儿。
移动端
27.保证所有组件都小于25K
这个限制是因为iPhone不能缓存大于25K的组件,注意这里指的是未压缩的大小。这就是为什么缩减内容本身也很重要,因为单纯的gzip可能不够。
28.把组件打包到一个复合文档里
服务器
29.Gzip组件
前端工程师可以想办法明显地缩短通过网络传输HTTP请求和响应的时间。毫无疑问,终端用户的带宽速度,网络服务商,对等交换点的距离等等,都是开发团队所无法控制的。但还有别的能够影响响应时间的因素,压缩可以通过减少HTTP响应的大小来缩短响应时间。
从HTTP/1.1开始,web客户端就有了支持压缩的Accept-Encoding HTTP请求头。
1
Accept-Encoding: gzip, deflate
如果web服务器看到这个请求头,它就会用客户端列出的一种方式来压缩响应。web服务器通过Content-Encoding相应头来通知客户端。
1
Content-Encoding: gzip
尽可能多地用gzip压缩能够给页面减肥,这也是提升用户体验最简单的方法。
30.避免图片src属性为空
Image with empty string src属性是空字符串的图片很常见,主要以两种形式出现:
straight HTML
<img src=””>
JavaScript
var img = new Image();
img.src = “”;
这两种形式都会引起相同的问题:浏览器会向服务器发送另一个请求。