内容部分
1.尽量减少HTTP请求数
页面大部分的响应时间都在下载页面上的各种组件:图片,样式表,脚本等等。减少组件数必然能够减少页面提交的HTTP请求数。这是让页面更快的关键。
合并文件是通过把所有脚本放在一个文件中的方式来减少请求数的,当然,也可以合并所有的CSS。
CSS Sprites是减少图片请求数量的首选方式。把背景图片都整合到一张图片中。
行内图片(Base64编码)用data: URL
模式来把图片放在(缓存的)样式表中。
2.减少DNS查找
DNS是有成本的,它需要20到120毫秒去查找给定主机名的IP地址。在DNS查找完成之前,浏览器无法从主机名下载任何东西。
DNS查找数等于页面上不同的主机名数,包括页面URL,图片,脚本文件,样式表等等组件中的主机名,减少不同的主机名就可以减少DNS查找。
HTTP客户端一般对同一个服务器的并发连接个数都是有限制的 。减少不同主机名的数量同时也减少了页面能够并行下载的组件数量,削减了避免DNS查找的响应时间,而减少并行下载数量却增加了响应时间。我的原则是把组件分散在2到4个主机名下,这是同时减少DNS查找和允许高并发下载的折中方案。
3.避免重定向
有一种常见的极其浪费资源的重定向,就是URL尾部缺少一个斜线。
当Web服务器接收到对末尾不含斜杠的url请求时(www.abc.com/home/efg
),服务器会搜索/home目录
下有没有名为efg
的文件,如果没有就把efg
当做目录处理,然后返回efg
目录下的默认首页,造成一次不必要的握手 。当Web服务器接收到的是末尾带斜杠的请求时就会直接当做目录处理。
4.Ajax可缓存
- 必须是GET请求
- 必须在response中发送正确的HTTP头信息:Expires
5.延迟加载组件
6.预加载组件
预加载可能看起来和延迟加载是相反的,但它其实有不同的目标。
通过预加载组件可以充分利用浏览器空闲的时间来请求将来会用到的组件(图片,样式和脚本)。
7.减少DOM元素的数量
一个复杂的页面意味着要下载更多的字节,而且用JavaScript访问DOM也会更慢。
8.跨域分离组件
分离组件可以最大化并行下载,但要确保只用不超过2-4个域,因为存在DNS查找的代价。
9.尽量少用iframe
用iframe可以把一个HTML文档插入到父文档里,重要的是明白iframe是如何工作的并高效地使用它。
<iframe>
的优点:
- 引入缓慢的第三方内容,比如标志和广告
- 安全沙箱
- 并行下载脚本
<iframe>
的缺点:
- 代价高昂,即使是空白的iframe
- 阻塞页面加载
- 非语义
10.杜绝404
HTTP请求代价高昂,完全没有必要用一个HTTP请求去获取一个无用的响应(比如404 Not Found),只会拖慢用户体验而没有任何好处。
css部分
11.避免使用CSS表达式
用CSS表达式动态设置CSS属性,是一种强大又危险的方式。例如,可以用CSS表达式把背景颜色设置成按小时交替的:
1 | background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" ); |
12.选择<link>
舍弃@import
页面被加载时,link
会同时被加载,而@impor
t引用的css
会等到页面加载结束后加载 。
13.避免使用滤镜
IE专有的AlphaImageLoader
滤镜可以用来修复IE7之前的版本中半透明PNG图片的问题。在图片加载过程中,这个滤镜会阻塞渲染,卡住浏览器,还会增加内存消耗而且是被应用到每个元素的,而不是每个图片,所以会存在一大堆问题。
最好的方法是干脆不要用AlphaImageLoader
,而优雅地降级到用在IE中支持性很好的PNG8图片来代替。如果非要用AlphaImageLoader
,应该用下划线hack:_filter
来避免影响IE7及更高版本的用户。
14.把样式表放在顶部
把样式表放在head里能让页面逐步渲染 。
js部分
15.去除重复脚本
除了产生没有意义的HTTP请求之外,多次对脚本求值也会浪费时间。因为无论脚本是否可缓存,在Firefox和IE中都会执行冗余的JavaScript代码。
避免不小心把相同脚本引入两次的一种方法就是在模版系统中实现脚本管理模块。典型的脚本引入方法就是在HTML页面中用SCRIPT标签:
1 | <script type="text/javascript" src="menu_1.0.17.js"></script> |
16.尽量减少DOM访问
用JavaScript访问DOM元素是很慢的,所以,为了让页面反应更迅速,应该:
- 缓存已访问过的元素的索引
- 先“离线”更新节点,再把它们添到DOM树上
- 避免用JavaScript修复布局问题
17.用智能的事件处理器
太多频繁执行的事件处理器被添加到了DOM树的不同元素上会导致页面不灵敏,这就是推荐使用事件委托的原因。
18.把脚本放在底部
脚本会阻塞并行下载,HTTP/1.1官方文档建议浏览器每个主机名下并行下载的组件数不要超过两个,如果图片来自多个主机名,并行下载的数量就可以超过两个。如果脚本正在下载,浏览器就不开始任何其它下载任务,即使是在不同主机名下的。
javascript, css
19.把JavaScript和CSS放到外面
用外部文件可以让页面更快,因为JavaScript和CSS文件会被缓存在浏览器。
20.压缩JavaScript和CSS
压缩具体来说就是从代码中去除不必要的字符以减少大小,从而提升加载速度。代码最小化就是去掉所有注释和不必要的空白字符(空格,换行和tab)。在JavaScript中这样做能够提高响应性能,因为要下载的文件变小了。
两个最常用的JavaScript代码压缩工具是JSMin和YUI Compressor,YUI compressor还可以压缩CSS。
图片
21.优化图片
尝试把GIF格式转换成PNG格式
22.优化CSS Sprite
- 在Sprite图片中横向排列一般都比纵向排列的最终文件小
- 组合Sprite图片中的相似颜色可以保持低色数,最理想的是256色以下PNG8格式
- “对移动端友好”,不要在Sprite图片中留下太大的空隙。虽然不会在很大程度上影响图片文件的大小,但这样做可以节省用户代理把图片解压成像素映射时消耗的内存。100×100的图片是1万个像素,而1000×1000的图片就是100万个像素了。
23.不要用HTML缩放图片
不要因为在HTML中可以设置宽高而使用本不需要的大图。如果需要
1 | <img width="100" height="100" src="mycat.jpg" alt="My Cat" /> |
那么图片本身(mycat.jpg)应该是100x100px的,而不是去缩小500x500px的图片。
24.用小的可缓存的favicon.ico
favicon.ico是放在服务器根目录的图片,它会带来一堆麻烦,因为即便你不管它,浏览器也会自动请求它,所以最好不要给一个404 Not Found
响应。而且只要在同一个服务器上,每次请求它时都会发送cookie,此外这个图片还会干扰下载顺序,例如在IE中,当你在onload中请求额外组件时,将会先下载favicon。
所以为了缓解favicon.ico的缺点,应该确保:
- 足够小,最好在1K以下
- 设置合适的有效期HTTP头,把有效期设置为几个月后一般比较安全,可以通过检查当前favicon.ico的最后修改日期来确保变更能让浏览器知道。
cookie
25.给Cookie减肥
保证cookie尽可能的小,以最小化对用户响应时间的影响。
- 清除不必要的cookie
- 保证cookie尽可能小,以最小化对用户响应时间的影响
- 注意给cookie设置合适的域级别,以免影响其它子域
- 设置合适的有效期,更早的有效期或者none可以更快的删除cookie,提高用户响应时间
26.把组件放在不含cookie的域下
当浏览器发送对静态图像的请求时,cookie也会一起发送,而服务器根本不需要这些cookie。所以它们只会造成没有意义的网络通信量,应该确保对静态组件的请求不含cookie。可以创建一个子域,把所有的静态组件都部署在那儿。 如果域名是www.example.org
,可以把静态组件部署到static.example.org
。
移动端
27.保证所有组件都小于25K
这个限制是因为iPhone不能缓存大于25K的组件,注意这里指的是未压缩的大小。这就是为什么缩减内容本身也很重要,因为单纯的gzip可能不够。
28.把组件打包到一个复合文档里
把各个组件打包成一个像有附件的电子邮件一样的复合文档里,可以用一个HTTP请求获取多个组件(记住一点:HTTP请求是代价高昂的)。用这种方式的时候,要先检查用户代理是否支持(iPhone就不支持)。
服务器
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
1
<img src=””>
JavaScript
1
2var img = new Image();
img.src = '';
这两种形式都会引起相同的问题:浏览器会向服务器发送另一个请求。
31.配置ETags
实体标签(ETags),是服务器和浏览器用来决定浏览器缓存中组件与源服务器中的组件是否匹配的一种机制(“实体”也就是组件:图片,脚本,样式表等等)。添加ETags可以提供一种实体验证机制,比最后修改日期更加灵活。一个ETag是一个字符串,作为一个组件某一具体版本的唯一标识符。唯一的格式约束是字符串必须用引号括起来,源服务器用相应头中的ETag
来指定组件的ETag:
1 | HTTP/1.1 200 OK |
然后,如果浏览器必须验证一个组件,它用If-None-Match
请求头来把ETag传回源服务器。如果ETags匹配成功,会返回一个304状态码,这样就减少了12195个字节的响应体。
1 | GET /i/yahoo.gif HTTP/1.1 |
32.对Ajax用GET请求
Yahoo!邮箱团队发现使用XMLHttpRequest
时,浏览器的POST请求是通过一个两步的过程来实现的:先发送HTTP头,再发送数据。所以最好用GET请求,它只需要发送一个TCP报文(除非cookie特别多)。IE的URL长度最大值是2K,所以如果要发送的数据超过2K就无法使用GET了。
POST请求的一个有趣的副作用是实际上没有发送任何数据,就像GET请求一样。正如HTTP说明文档中描述的,GET请求是用来检索信息的。所以它的语义只是用GET请求来请求数据,而不是用来发送需要存储到服务器的数据。