1、减少HTTP请求
why
减少响应时间。
how
- CSS Sprites
- 合并样式脚本
- 内联图片(使用data:URL模式可以在web页面中包含图片但不需要额外的HTTP请求)
2、使用内容发布网络(CDN)
why
浏览器是根据域(Domain)来缓存内容资源的,只要域不一样,那么它就需要重复下载这些资源,而且使用同样的方式将它们缓存起来。
带来的问题:重复地下载,这会占用网络资源和缓存空间。
how
如果有很多站点,它们之间可以共享某些内容(例如javascript,css,image等),那么与其每个站点放一份,就不如将他们统一地存在在一个地方,这样就可以减少下载的次数和缓存的体积了。
如:引用jquery cdn
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
3、添加Expires头
why
使内容具有缓存性
how
Expires: Thu, 01 Dec 1994 16:00:00 GMT (必须是GMT格式)
通过HTTP的META设置expires和cache-control
<meta http-equiv="Cache-Control" content="max-age=7200" />
<meta http-equiv="Expires" content="Mon, 20 Jul 2009 23:00:00 GMT" />
上述设置仅为举例,实际使用其一即可。这样写的话仅对该网页有效,对网页中的图片或其他请求无效,并不会做任何cache。
4、压缩组件
why
减小文件体积,提升页面加载速度
how
压缩脚本和样式表
5、样式置顶
why
放在底部可能会出现白屏,会阻塞页面的逐步呈现
注意:使用link,不使用@import(可能出现白屏,以及下载组件无序性)
6、脚本置底
why
页面既可以逐步呈现,也可以提高资源下载的并行度
最差情况:放在顶部
- 会阻塞后面内容的呈现
- 会阻塞其它组件的下载
7、避免使用CSS表达式
why
表达式可能会运算很多遍、影响页面性能
how
实现动态CSS可以使用javascript控制
$(function () {
$("dom").css("background-color",(new Date()).getHours()%2?"#EEE":"#BBB");
});
8、使用外链JavaScript和CSS
why
提高样式和脚本复用性
注意:纯粹而言,内联速度比外链快,因为外链额外增加了http请求,但是由于浏览器缓存,当多页面引用了同一个样式表或脚本文件时,反而减少了HTTP请求,实现复用。
how
<link rel="stylesheet" type="text/css" href="style.css" />
<script type="text/javascript" src="main.js" />
9、减少DNS查找
why
查找DNS是需要花费时间的,通常浏览器在查找给定的IP地址要花费20~120毫秒的时间,在DNS完成查找之前,浏览器无法从主机名下载任何东西。
how
最理想的情况:只使用一个主机名,既减少了DNS查找,又最大化了并行下载。(只针对页面组件很少(1个或2个)的情况)
更现实的情况:使用2个,但不多于4个主机名,这样在减少DNS查找和允许高度并行下载之间做出了比较好的均衡。
10、精简JavaScript和CSS
why
减小文件大小,改善加载时间
how
- 从代码中移除不必要的字符(包括空格、注释、换行符等)
- 精简JS代码可使用JSMin
- 精简CSS代码,合并相同的类,移除不使用的类,使用缩写,如“#EEEEEE”写成“#EEE”,“0px”写成“0”。
11、避免重定向
why
重定向是指用户的原始请求重新转向到了其它请求
301 Moved Permanently
:这个状态码标识用户所请求的资源被移动到了另外的位置,客户端接收到此响应后,需要发起另外一个请求去下载所需的资源。
302 Found
:这个状态码标识用户所请求的资源被找到了,但不在原始位置,服务器会回复其他的一个位置,客户端收到此响应后,也需要发起另外一个请求去下载所需的资源。
目前我们一直只要区分301和302即可。他们本质上的区别到底是什么呢?301表示永久重定向,302表示临时重定向。
how
在定义链接地址的href属性的时候,尽量使用最完整的、直接的地址。例如:
使用 www.google.com
而不是google.com
使用cn.xxxx.com
而不是xxxx.com
使用www.google.com.hk
而不是google.com
使用www.site.com/products/
而不是www.site.com/products
12、移除重复脚本
why
重复脚本损伤性能:不必要的HTTP请求及执行JS所浪费的时间
how
确保脚本只被加载一次。使用模块化工具如requireJS或seaJS管理脚本。
13、配置ETag(实体标签)
它的作用是用一个特殊的字符串来标识某个资源的“版本”,客户端(浏览器)请求的时候,比较ETag如果一致,则表示该资源并没有被修改过,客户端(浏览器)可以使用自己缓存的版本,避免重复下载。
服务器检测缓存组件和原始服务器组件匹配的方式
如果缓存组件过期了或者用户明确地重新加载了页面,浏览器在重用之前必须首先检查它是否有效。这称作一个条件GET请求。虽然浏览器必须产生这个http请求,但是仍比简单地下载所有已过期的组件效率高。如果浏览器组件是有效的(相互匹配)原始服务器则不会返回整个组件,而是返回304 not modifed状态码。
检测匹配有两种方式
- 比较最新修改日期
第一次请求响应
————>
GET /i/xx.jpg HTTP 1.1
HOST www.xxx.com
<————
HTTP 1.1 20 OK
Last-Modified:true .12 dec 2015 03:03:09 GMT
Content-Length:1024
第二次请求响应
————>
GET /i/xx.jpg HTTP 1.1
HOST www.xxx.com
If-Modified-Since:True,12 dec 2015 03:03:09 GMT
<————
HTTP 1.1 304 not modifed
- 比较实体标签
实体是我们之前提到的组件的另一种称呼。ETag是唯一标识了一个组件的一个特定版本的字符串,必须带上引号。这种为验证实体提供了更为灵活的机制——可以根据user-agent,accept-language头而改变。
第一次请求响应
————>
GET /i/xx.jpg HTTP 1.1
HOST www.xxx.com
<————
HTTP 1.1 20 OK
Last-Modified:true .12 dec 2015 03:03:09 GMT
ETag:"10c34ba-8ba-abds3b3"
Content-Length:1024
第二次请求响应
————>
GET /i/xx.jpg HTTP 1.1
HOST www.xxx.com
If-Modified-Since:True,12 dec 2015 03:03:09 GMT
If-None-Match:"10c34ba-8ba-abds3b3"
<————
HTTP 1.1 304 not modifed
ETag带来的问题
- 如果部署在服务器场环境中,配置不当的话,可能每个服务器会对相同的资源生成不一样的ETag,这样就增加了重复下载的可能性。
ETag的优势和特点
- 可以更加精确地判断资源是否被修改,因为它不是一个时间值,而是对时间经过处理的一个长整型数值(当然具体算法我们目前还不得而知)。
- 浏览器发起新请求时需要包含 If-None-Match。
14、使Ajax可缓存
why
由于AJAX其实也是需要发起请求,然后服务器执行,并将结果(通常是JSON格式的)发送给浏览器进行最后的呈现或者处理,所以对于网站设计优化的角度而言,我们同样需要考虑对这些请求,是否可以尽可能的利用到缓存的功能来提高性能。
how
对于AJAX而言,有一些特殊性,并不是所有的AJAX请求都是可以缓存的。
- POST的请求,是不可以在客户端缓存的,每次请求都需要发送给服务器进行处理,每次都会返回状态码200。(这里可以优化的是,服务器端对数据进行缓存,以便提高处理速度)
- GET的请求,是可以(并且默认)在客户端进行缓存的,除非指定了不同的地址,否则同一地址的AJAX请求,不会重复再服务器执行,而是返回304。
有的时候,我们可能希望GET请求不被缓存,有几种做法来达到这样的目的。
- 每次调用的时候,请求不同的地址(可以在原始地址后面添加一个随机的号码)。
- 如果你所使用的是jquery的话,则可以考虑禁用AJAX的缓存。
$.ajaxSetup({ cache: false });
15、使用GET来完成Ajax请求
why
- 1、POST请求,不能使用客户端缓存
- 2、GET请求,可以使用客户端缓存
这个意义上来讲,使用GET会比POST而言,因为减少了请求数和数据的重复传输,有更好的一个性能表现。
在使用XMLHttpRequest(目前的AJAX都是基于它实现的)的时候,浏览器中的POST实现为两步走的过程,首先发送头部信息,然后再发送数据。但如果是使用GET的话,就只有一个TCP的包发送出去(除非有大量的Cookie),这样无疑可以提高性能。
【备注】一个TCP包的尺寸大约为1452字节。 除此之外,显示的项目中,并不是总能使用GET的,例如长度方面可能会有限制:The maximum URL length in IE is 2K, so if you send more than 2k data you might not be able to use GET.
16、减少DOM元素数量
why
DOM(Document Object Model)
文档对象模型
HTML DOM
定义了访问和操作 HTML
文档的标准方法。DOM
将 HTML
文档表达为树结构。
减少页面的DOM
元素数量,有助于减小页面体积,并且也降低了维护这份DOM
树的成本。
how
- 1、避免不正确地使用服务器控件。
- 2、减少不必要的内容(并不是所有的内容都必须放在页面上面的)。
如果数据量大,可以考虑分页,或者按需加载
17、避免404
why
什么情况下会发生404错误?
404 意味着Not Found,意思是说未找到资源。至少会有两种原因导致404错误:
- 1、该资源按理说是要有,但我们没有提供。用户按照正常的方式来请求,所以资源找不到。
- 2、该资源本来就不存在,用户按照不正常的方式来请求,当然还是找不到。
404错误会有什么影响?
① 看不到的影响:有时候,404错误发生了,用户可能根本没有感觉到。
- 例如请求favicon.ico文件,或者请求了某个不存在的脚本文件、样式表、图片文件,页面还是会按照正常的方式进行呈现。
- 丢失的脚本文件、样式表、图片文件,会导致页面的某些行为、界面效果出现异常(也可能不是很明显)
- 最大的问题可能是性能方面的影响。尤其是如果请求一个不存在的脚本文件,因为浏览器在请求脚本文件的时候,即便是返回404,它也会尝试去按照Javascript的方式解析响应中的内容。这无疑会增加很多处理的时间,而因为该文件不存在,所以这些都是无用功。
② 看得到的影响:
- 如果用户请求的某个页面不存在,那么他将收到明确的回应
- 默认情况下,他将收到一个标准的错误页面(请注意:不少用户会被这个页面吓到)
how
避免404错误发生的措施:
- 为网站提供favicon.ico。
- 在发布网站前的测试工作中,运行Link checker工具,确保所有链接都是能够访问到的。这个工具是W3C发布的,完全免费,你值得拥有。
- 为了避免用户收藏绝对地址(customer.aspx),给后期更新带来隐患。可以考虑在设计阶段采用 Url Rewriting 或者 Routing 等技术来实现更加友好和灵活的地址(例如/Customer),以后如果业务逻辑有变化,只需要修改一下路由规则即可。
第三条措施,同样可以尽可能地减少用户手工输入地址出错的机会。
18、减少Cookie的大小
why
如果对某个域(Domain)保存了Cookie,那么针对这个域的所有请求,都会发送这些所有的Cookie(哪怕当前请求根本用不着,例如针对图片的请求),大量的、重复的发送Cookie毫无疑问会增加网络的流量,并因此而降低请求被执行的性能。
how
从技术上说,这个文件的内容是由网站控制的,它可以决定要写什么内容在里面,他也可以决定是否要加密。唯一的一个限制,这个文件的体积不允许超过4KB。
19、使用无Cookie的域
why
比如图片 CSS 等,Yahoo! 的静态文件都在主域名以外,客户端请求静态文件的时候,减少了 Cookie的反复传输对主域名的影响。
只有访问主域名的时候才需要保存cookie,而cookie会自动地发送给当前域的所有请求。
20、不要使用滤镜
why
Filters这个功能是IE当年为了提供更加丰富的一些页面效果而设计出来的。
不仅仅是别的浏览器可能不支持,IE从9.0版本开始也放弃了这方面的支持。
21、不要在HTML中缩放图片
why
有时得到的图片尺寸和具体显示尺寸不一样,为了在网页中显示出希望的尺寸,通常会通过下面的方法把图片进行缩放:
<img width="100" height="100" src="pic.jpg" alt="my pic"/>
浏览器下载到原始图片之后,如果原始尺寸与目标尺寸不符,就会需要对图片进行缩放(拉伸或者缩小),以便实现刚才所提到的目的。
how
我们需要在网页中显示什么尺寸的图片,就请图片设计人员提供什么尺寸的图片,而不是在网页中进行缩放。
22、缩小favicon.icon并缓存
why
- 1、每个网站都应该有该文件,浏览器在访问任何页面的时候,总是会尝试去请求这个文件(如果本地没有的话)。
- 2、该文件通常应该命名为favicon.ico ,如果希望使用别的名称或者格式(例如PNG),则需要在页面的头部(Head)中定义引用(下面两句中的第一句是必须的)
<link rel="shortcut icon" href="http://example.com/favicon.ico" type="image/vnd.microsoft.icon">
<link rel="icon" href="http://example.com/favicon.ico" type="image/vnd.microsoft.icon">
- 3、该文件可以直接放在网站根目录,但也可以放在其他的主机,或者你想要的任何位置。如果不在默认的根目录下面,也是需要通过上面所提到的引用方式定义。
how
使它尽量在1KB左右。想比较其他的格式(PNG,GIF等),该文件默认的格式为ico,这种文件通常较小。要创建favicon.ico文件,可以使用 http://www.favicon.cc/
提供的在线免费服务。
使它能够缓存。 由于该文件使用很频繁,所以缓存显得很重要。对于这个文件而言,可以设置永不过期(或者过期时间长一些)。
将该文件放在单独的主机中,可以避免在请求该文件时发送cookie。
23、避免空的src和href
why
空的src和href都会导致多余的HTTP请求,虽然不影响加载时间,但是会对服务器产生不必要的流量和压力,严重的以至于影响整个网站的用户体验。
例子:
在页面加载的过程中,一个有着空src属性的img元素被JavaScript动态地赋值。这样做的问题是,在脚本执行之前元素就被浏览器渲染了(尤其是当你把脚本放到文档最后的时候)。所以浏览器依然会发起一个HTTP 请求,虽然它是一个空值。
雅虎的团队指出,如果你将img的src留空,可能你的本意是暂时不要显示任何图片,但在不同的浏览器其实还是会有一些额外的请求发生。
例子:
同样的问题也发生在href 这个属性上。有些时候,开发人员想用超链接来触发JavaScript的一个交互。这时问题就来了,当用户触发了“单击”操作,如果 href 是空的那么浏览器就向服务器发送一个HTTP 请求。
how
- 避免空的src和herf值。
- 解决留空src属性的问题:
- 你可以将初始图片设置为一个很小的默认图片(这个图片设置永不过期),而不是留空。
解决留空href属性的问题:
- 给
<a>
标签以href
属性,并不连接到实际的页面:
<a href="#"></a>
<a href="#nogo"></a>
<a href="##"></a>
<a href="###"></a>
<a href="void(0);"></a>
<a href="void(0)"></a>
<a href=";"></a>
<a href=""></a>
- 禁止跳转,并添加
cursor:pointer
样式
<style type="text/css">
a{cursor: pointer}
</style>
<a>点击一</a>
<a onclick="doSomething()">点击二</a>
- 给
a
标签创建一个带有描述信息的href
属性,并监控click
事件调用preventDefault()
函数。
<a href="#Something_De scriptive" id="my_id">Trigger</a>
<script>
$("#my_id").click(function(e){
e.preventDefault(); // 取消单击事件的默认动作以阻止链接的跳转。
// 其他的代码
});
</script>
优点:
让<a>
够响应键盘事件并获得焦点(从而屏幕阅读器能够读出背后的内容,增强可访问性)
优雅降级,在网络连接很差,还没有加载到CSS的时候,<a>
依然有手型与正常的link样式。
参考:YSlow团队的23条“Web性能最佳实践和规则”+《高性能网站建设指南》
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。