该书介绍了14条优化规则:
1. 减少HTTP请求
-
图片地图
调整几个image标签的布局,就像拼图一样形成一张大图;
-
雪碧图
将一些 icon 或者图片拼接在一张图上,减少图片的请求量
-
内联图片
通过 data:url 的形式引入图片,减少图片的请求量
- 用url中的数据描绘图片信息,且存在数据大小(100KB)的限制;
- 跨页面时,在页面中使用的内联图片不会缓存,但在样式表中使用可以缓存在样式表;
-
合并脚本和 样式表
将多个脚本合并成一个,多个样式表也合并成一个。一个页面应该最多使用一个脚本和一个样式表;
2. 使用CDN
-
CDN
静态资源服务器根据地理距离快速响应资源
- 优秀:CDN是一个静态web服务器,会选择最短响应时间或者网络活跃度最小的服务器来响应资源;
- 缺点:CDN服务性能下降的话,资源响应时间也会受影响,可以使用两个CDN服务提供商。
3. 添加 Expire 头
即浏览器对图片、样式、脚本 进行强缓存;
如果请求头中有
Expire或Cache-Control字段,浏览器会缓存请求到内存或者磁盘中,下次请求的时候看有没有过期,没有过期的话直接返回响应体;另外缓存到内存的数据关闭浏览器标签后会清除,缓存到磁盘中的不会清除;
-
在请求头中添加 Expire 字段
设置资源过期时间如
Expires: Tue, 15 Apr 2023 20:00:00 GMT; -
在请求头中添加 Cache-Control 字段
- 优先级更高会覆盖
Expire字段; - 设置强缓存的过期时间相关配置,其中
max-age字段用来设置相对过期时间如Cache-Control: max-age=315360000;
- 优先级更高会覆盖
4. 压缩资源
大多数是对超过500B的html、脚本和样式资源进行压缩;
请求头通过
Accept-Encoding:gzip,deflate设置压缩的格式,响应头通过Content-Encoding:gzip返回响应数据的压缩格式;
-
响应头设置
Vary: Accept-Encoding比如有个代理服务器,分别收到不同浏览器访问同一个url的请求,且一个请求头有
Accept-Encoding:gzip一个没有,响应头设置了Vary: Accept-Encoding后会缓存服务器响应的压缩了的和未压缩的两个版本的资源;
5. 将样式表放在顶部
- 放在body底部,在DOM Tree构建完成之后开始构建render Tree,计算布局然后绘制网页,等css文件加载后,开始构建CSSOM Tree,并和DOM Tree一起构建render Tree,再次计算布局重新绘制;会造成
无样式内容的闪烁; - 放在head中,先加载css,构建CSSOM,同时构建DOM Tree,CSSOM和DOM Tree构建完成后,构建render Tree,进行计算布局绘制网页。
6. 将脚本放在底部
-
放在head中,整个页面的呈现和下载会被打断,直到脚本加载完毕。
-
可以使用script标签中的
defer和async属性来异步加载,script标签的位置将不在受限;
- 绿色表示 html解析过程
- 蓝色表示 脚本下载过程
- 红色表示 脚本执行过程
7. 避免 CSS表达式
仅IE5及其以后版本支持在CSS中使用expression;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style type="text/css">
div {
background-color: expression(altBgColor(this));
}
</style>
<script type="text/javascript">
function altBgColor(elem) {
elem.style.backgroundColor = 'red';
}
</script>
</head>
<body>
<div id="app">hhh</div>
</body>
</html>
注意: 一般不建议使用expression,因为expression比较消耗资源,如果改变大小、滚动和鼠标移动都会进行求值。可以改为在事件处理器中修改样式。
8. 使用外部Javascript和CSS
- 内联Javascript和CSS在HTML会减少请求数量,适合用户较少访问且访问页面较少的网站或者对响应速度要求较高的主页;
- Javascript和CSS是外部文件的话,浏览器就能缓存他们,HTML文档也会大小会减小,适合用户经常访问的网站;
9. 减少DNS查询
通常浏览器查找一个给定的主机名的IP堵住要花费20~120毫秒,在用户请求了一个主机名后,DNS信息会留在操作系统的DNS缓存中;
- 建议将页面的资源分别放在至少2个,但不要超过4个主机名下,这样既可以减少DNS查找又可以并行下载;
10. 精简Javascript
- 使用
JSMin对Javascript进行代码精简, 或者Dojo compressor进行混淆(移除空白和注释和改写代码比如变量名变得更简短); - 内联
Javascript - 精简
CSS, 移除空白和注释,移除不必要的字符串(用 0 代替 0px);
11. 避免重定向
- 当Web服务器向浏览器返回一个重定向时,响应中就会有一个范围在3xx的状态码,表示用户代理必须执行进一步操作才能完成请求。最常用的重定向状态码是301和302。
- 重定向延迟了整个HTML文档的传输,在HTML资源加载前不会渲染页面;
12. 移除重复脚本
- 导致脚本重复的主要因素:团队的大小和脚本的数量。
- 重复脚本损伤性能的主要方式:不必要的HTTP请求和执行JavaScript所浪费的时间。
13.配置 ETag
即浏览器对图片、样式、脚本 进行协商缓存;
-
Last-Modified和If-Modified-Since- 服务器通过
Last-Modified响应头来返回资源的最新修改日期,浏览器缓存了该资源及其最新修改日期。 - 下一次请求该资源时浏览器会使用
If-Modified-Since头将最新日期传会到原始服务器进行比较。 - 如果原是服务器上资源的最新修改日期与浏览器传回的值匹配,会返回资源并且状态码为
304;
- 服务器通过
-
ETag和If-None-Match- 优先级更高会覆盖
Expire字段; - 服务器通过
ETag响应头来返回资源的ETag,浏览器缓存了该资源及该字段。 - 下一次请求该资源时浏览器会使用
If-None-Match头将上次存储的ETag传回原始服务,如果ETag是匹配的,会返回资源并且状态码为304;
- 优先级更高会覆盖
-
ETag的问题分布式服务器存储的情况下,计算 Etag 的算法如果不一样,会导致浏览器从一台服务器上获得原始资源后到另外一台服务器上进行验证时现 Etag 不匹配的情况,从而而导致重新重新获取资源;
1. 如果使用Last-Modified不会出现任何问题,可以直接移除ETag,google的搜索首页则没有使用ETag。 2. 确定要使用ETag,在配置ETag的值的时候,移除可能影响到资源集群服务器验证的属性,例如只包含资源大小和时间戳。
14. 使Ajax可缓存
-
确保Ajax请求遵循性能指导,尤其是要配置Expires头,缓存资源;
-
Ajax一个明显的优点就是向用户提供即时反馈,因为它异步的从后端Web服务器请求信息,但是也并不是说使用Ajax就保证用户不需要等待,用户是否需要等待的关键硬是还在于Ajax是主动的请求还是被动的请求。
-
被动请求(Passive Request)和 主动请求(Active Request)
-
被动请求是为了将来使用而预先发起的,比如预加载;
-
主动请求(Active Request)是基于用户当前的操作发起的;
-