HTTP头部
压缩头部
如果浏览器和服务器都支持的话,可以使用压缩来减小响应的大小。
请求头: Accept-Encoding(浏览器可以支持的web服务器返回内容压缩编码类型): gzip, deflate
响应头:Content-Encoding: gzip
条件get请求
听起来很高大上的样子,其实就是在发送get请求的时候加上一个If-Modified-Since字段,这个时候是属于协商缓存的,服务器会根据If-Modified-Since中的时间和Last-Modified的时间来决定是否返回304.这个时候服务器不再发送响应体(返回的消息就只有响应头??)。
Expires
如果响应头中包含expires字段,就是用的强制缓存(cache-control 和expires)了,在客户端进行判断,只要没有过期就会使用缓存版本,而不会进行任何HTTP请求。
Keep-Alive
connection:可以取值为close或者keep-alive
- 在HTTP 1.0中,客户端的每次请求都要求建立一次单独的连接,在处理完本次请求后,就自动释放连接。因此如果要请求一个HTML文件,其中包含10张图片就要产生11个TCP连接。当然多个TCP连接可以并行,但是默认的情况下大部分浏览器打开5~10个并行的TCP连接。
- 在HTTP 1.1中则可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求。和1.0中不同的是,多个请求可以共用一个TCP连接,而不用每次都是请求–响应–释放。
再说下HTTP2.0中的多路复用问题,事实上,1.1中的长连接每个请求是依次进行的,但是2.0中不是这样。
优化方案
1. 减少HTTP请求数量
事实上,解析一个网页只有10%–20%左右的时间花在请求html文档上,剩余80%~90%的时间花在请求html文档所用到的组件上,包括图片/js/css
图片地图
将导航栏的多个图标用一张图片代替,根据用户点击的位置跳到指定的链接。分为服务器端图片地图和客户端图片地图
雪碧图
根据background-position来设置
内联图片
内联图片不会产生http请求,允许小块数据内联为‘立即数’,数据就在url自身当中。
格式:
缺点:
- 浏览器不会缓存内联图片资源
- IE8以下不支持
- 超过100KB的图片,base64编码会使图片大小增大,导致网页整体下载速度减慢
合并脚本和样式表
具体应该用到什么工具呢?如果最后合成一个资源,那减少了HTTP请求和每个页面下载了不需要的代码,该如何取舍呢?
2.使用内容分发网络(CDN)
3.使用expires
expires前面已经有提到了,http1.1中引入了cache-control字段,主要原因是expires的过期时间是一个绝对时间。因此要求服务器和客户端的时间基本上要保持同步。
4. 压缩组件
前面提到过,在请求头中添加Accept-Encoding可以设置浏览器支持的web服务器返回内容压缩编码类型。服务器在响应头中添加Content-Encoding。gzip是最流行和最有效的压缩方法。常用的还有deflate。
那我们应该压缩哪些内容呢?html css js以及响应的xml和json文本都是可以压缩的。图片和pdf不应该压缩。
代理缓存问题
想像一个场景,当浏览器通过代理来发送请求的情况下。假设针对某个url的第一个请求是不支持压缩的,所以服务器的响应肯定也是未压缩的,因此代理的缓存也是未压缩的。但是当第二个请求来自于一个支持压缩的浏览器的访问,那么代理还是会以之前缓存的未压缩的进行响应。反之,当第一个请求来自于一个支持压缩的浏览器,但是第二个请求来自于不支持压缩的浏览器,情况也就更加严重了。
解决方案:在响应中添加vary:Accept-Encoding,服务器根据一个或多个请求头来改变缓存的响应。这样代理就可以根据Accpet-Encoding的值的不同,缓存多个响应版本。
5. 将样式表放在顶部
白屏
这里不得不说一句的是,如果将css放在底部或者是在head中以@import的方式引入样式表,都有可能会导致白屏现象,然后所有内容同时涌上屏幕。
无样式内容闪烁(FOUC)
出现无样式现象是图片或其他的内容已经显示了,但是当css样式加载完了以后又重新渲染显示。原因同样是是因为将css放在了底部。
白屏和FOUC的选择:如果将css放在底部,浏览器有两种选择,白屏或者FOUC。如果css仍在加载,构建和呈现树就是一种浪费—-白屏。逐步显示,css加载完了再更新—FOUC
所以将样式表放在底部可能会导致白屏和FOUC(Flash of unstyled content)
6. 将脚本放在底部
在下载解释执行js文件的时候,是不能下载其他的图片资源以及css样式的。
在下载除js的资源外,其他资源都是可以并行下载的。为什么js不能并行下载呢?
第一,多个js之间可能有依赖关系。
第二,脚本可能使用document.write来修改页面内容。
defer
正常来说脚本都是下载了然后就会解释执行,但是加上defer之后,就告诉浏览器,可以不用对我立即执行。但是,在用defer声明的脚本中,是不能出现document.write的;并且,其他脚本也是不能引用该defer脚本内的变量的。
7. 避免使用css表达式
因为css表达式会被频繁地进行计算,当页面呈现和改变,滚动,用户鼠标拖拽都会重新求值。
解决方案
一次性表达式,即在css中调用js函数。
1234567p{background-color: expression(altBgcolor(this))}js:function altBgcolor(elem){elem.style.backgroundColor = ....}或者直接在js中绑定事件函数中修改css样式。
8. 使用外部js和css
如果将所有js文件都放在html中,第一次加载,内联式的性能会优于外联式。但是外联式有一个优点是可以缓存js和css文件。
这里又不得不说一个重用的问题,应该把各个页面相同的css部分提取出来,这样请求的时候就可以从缓存中获取。同时还有一个大的优化方向,即第一条说的请求数量越少越好。
9. 减少DNS的查找
浏览器默认会将DNS和对应的IP缓存起来。但是服务器可以在返回的DNS记录中包含一个TTL(time-to-live),来表明可以被缓存的时间。但有些时候浏览器会忽略TTL而设置自己的时间限制。
所以如果浏览器支持keep-alive的话,那么一个持久的TCP链接将会一直使用,直至出现一定的空闲时间为止。(如IE的keepAliveTimeout:默认为1分钟)
10. 精简的js
注释、不必要的空白字符都会被移除。
混淆:移除注释和空白,同时将函数和变量的名字转化为更短的字符串。但是混淆可能会引入错误;维护和调试也更加困难。
常用的压缩工具:JSMin
精简CSS:合并相同的类,移除不使用的类。
11. 避免重定向
301:永久性重定向。返回301的时候通常会返回一个Location:url字段,表示需要被重定向到的url。
|
|
12. 删除重复的脚本
13. 配置或移除Etag
ETag: entity tag实体标签
ETag是为了解决if-modefied-Since的时间只能精确到s,并且可能内容并未改变,只是一些不重要的信息改变了,也会导致重新下载。
ETag的缺点:如果是在一个集群系统中,当浏览器从一台服务器中获取了原始组件之后,如果再向另一天服务器请求相同的内容,ETag是不会匹配的。
14. 使用AJAX缓存
加入cache-control字段和expires字段,来让ajax请求也支持缓存。