前端性能优化 缓存篇
缓存是所有性能优化的方式中最重要的一步。
缓存在宏观上可以分成两类:私有缓存和共享缓存。共享缓存就是那些能被各级代理缓存的缓存。私有缓存就是用户专享的,各级代理不能缓存的缓存。
微观上可以分三类:浏览器缓存、代理服务器缓存、网关缓存、 数据库缓存。
一、浏览器缓存(一般只有GET请求才会被缓存)
注意,浏览器缓存和存储(localStorage 和sessionStorage)不是一回事。
缓存:资源文件(比如图片)在本地存有副本,浏览器下次请求的时候,可能直接从本地磁盘里读取,而不会重新请求资源的url。
缓存分为:
- 强缓存;
- 协商缓存。
强缓存
不用请求服务器,直接使用本地的缓存。
强缓存是利用 http 响应头中的 Expires
或 Cache-Control
实现的。
浏览器第一次请求一个资源时,服务器在返回该资源的同时,会把上面这两个属性放在response header中。比如:
这两个response header属性可以只启用一个,也可以同时启用。当response header中,Expires和Cache-Control同时存在时,Cache-Control的优先级高于Expires。
下面讲一下二者的区别。
1. Expires
:服务器返回的绝对时间。
是较老的强缓存管理 response header。浏览器再次请求这个资源时,先从缓存中寻找,找到这个资源后,拿出它的Expires跟当前的请求时间比较,如果请求时间在Expires的时间之前,就能命中缓存,否则就不行。
如果缓存没有命中,浏览器直接从服务器请求资源时,Expires Header在重新请求的时候会被更新。
缺点:
由于Expires是服务器返回的一个绝对时间,存在的问题是:服务器的事件和客户端的事件可能不一致。在服务器时间与客户端时间相差较大时,缓存管理容易出现问题,比如随意修改客户端时间,就能影响缓存命中的结果。所以,在http1.1中,提出了一个新的response header,就是Cache-Control。
2. Cache-Control
:服务器返回的相对时间。
http1.1中新增的 response header。浏览器第一次请求资源之后,在接下来的相对时间之内,都可以利用本地缓存。超出这个时间之后,则不能命中缓存。重新请求时,Cache-Control会被更新。
协商缓存
协商缓存:浏览器发现本地有资源的副本,但是不太确定要不要使用,于是去问问服务器。
当浏览器对某个资源的请求没有命中强缓存(也就是说超出时间了),就会发一个请求到服务器,验证协商缓存是否命中。
协商缓存是利用的是两对Header:
- 第一对:Last-Modified、If-Modified-Since
- 第二对:ETag、If-None-Match
1. Last-Modified
、If-Modified-Since
。过程如下:
(1)浏览器第一次请求一个资源,服务器在返回这个资源的同时,会加上 Last-Modified
这个 response header,这个header表示这该资源在服务器上的最后修改时间:
(2)浏览器再次请求这个资源时,会加上If-Modified-Since这个 request header,这个header的值就是上一次返回的Last-Modified的值:
(3)服务器收到第二次请求时,会比对浏览器传过来的If-Modified-Since和资源在服务器上的最后修改时间Last-Modified,判断资源是否有变化。如果没有变化则返回304 Not Modified,但不返回资源内容(此时,服务器不会返回 Last-Modified 这个 response header);如果有变化,就正常返回资源内容(继续重复整个流程)。
(4)浏览器如果收到304的响应,就会从缓存中加载资源。
缺点:
Last-Modified
、If-Modified-Since
一般来说都是非常可靠的,但有可能出现的问题是:服务器上的资源变化了,但是最后的修改时间却没有变化。这一对header就无法解决这种情况。于是,下面这一对header出场了。
2. ETag
、If-None-Match
。过程如下:
(1)浏览器第一次请求一个资源,服务器在返回这个资源的同时,会加上ETag这个 response header,这个header是服务器根据当前请求的资源生成的唯一标识。这个唯一标识是一个字符串,只要资源有变化这个串就不同,跟最后修改时间无关,所以也就很好地补充了Last-Modified
的不足。如下:
(2)浏览器再次请求这个资源时,会加上If-None-Match这个 request header,这个header的值就是上一次返回的ETag的值:
(3)服务器第二次请求时,会对比浏览器传过来的If-None-Match和服务器重新生成的一个新的ETag,判断资源是否有变化。如果没有变化则返回304 Not Modified,但不返回资源内容(此时,由于ETag重新生成过,response header 中还会把这个ETag返回,即使这个ETag并无变化)。如果有变化,就正常返回资源内容(继续重复整个流程)。这是服务器返回304时的 response header:
(4)浏览器如果收到304的响应,就会从缓存中加载资源。
总结
协商缓存需要配合强缓存使用,你看下面这个截图中,除了Last-Modified这个header,还有强缓存的相关header,因为如果不启用强缓存的话,协商缓存根本没有意义。
如果资源已经被浏览器缓存下来,在缓存失效之前,再次请求时,默认会先检查是否命中强缓存,如果强缓存命中则直接读取缓存,如果强缓存没有命中则发请求到服务器检查是否命中协商缓存,如果协商缓存命中,则告诉浏览器还是可以从缓存读取,否则才从服务器返回最新的资源。这是默认的处理方式,这个方式可能被浏览器的行为改变:
- 当ctrl+f5 强制刷新网页时,直接从服务器加载,跳过强缓存和协商缓存;
- 当 f5 刷新网页时,跳过强缓存,但是会检查协商缓存;
二、使用 CDN(用 CDN 托管静态资源)(使用 CDN,抛开无用的 cookie)
要知道,浏览器第一次打开页面的时候,浏览器缓存是起不了作任何用的;使用CDN,效果就很明显。
CDN 缓存,也叫网关缓存、反向代理缓存。浏览器先向CDN网关发起WEB请求,网关服务器后面对应着一台或多台负载均衡源服务器,会根据它们的负载请求,动态地请求转发到合适的源服务器上。
通过在现有的 Internet 中增加一层新的CACHE(缓存)层,将网站的内容发布到最接近用户的网络”边缘“的节点,使用户可以就近取得所需的内容,提高用户访问网站的响应速度。
cdn 从技术上全面解决由于网络带宽小、用户访问量大、网点分布不均等原因,提高用户访问网站的响应速度。CDN网络是在用户和服务器之间增加Cache层,主要是通过接管DNS实现,将用户的请求引导到Cache上获得源服务器的数据。
使用了 CDN 缓存后的网站的访问过程变为:
- 用户输入访问的域名,操作系统向 LocalDns 查询域名的ip地址;
- LocalDns 向 ROOT DNS 查询域名的授权服务器(这里假设LocalDns缓存过期);
- ROOT DNS将域名授权dns记录回应给 LocalDns,LocalDns得到域名的授权dns记录后,继续向域名授权dns查询域名的ip地址;
- 域名授权dns 查询域名记录后(一般是CNAME),回应给 LocalDns,LocalDns 得到域名记录后,向智能调度DNS查询域名的ip地址;
- 智能调度DNS 根据一定的算法和策略(比如静态拓扑,容量等),将最适合的CDN节点ip地址回应给LocalDns,LocalDns将得到的域名ip地址,回应给用户端,用户得到域名ip地址后,访问站点服务器;
- CDN节点服务器应答请求,将内容返回给客户端.(缓存服务器一方面在本地进行保存,以备以后使用,二方面把获取的数据返回给客户端,完成数据服务过程)
三、应用案例
让 ajax 请求可以被缓存
Ajax 的调用和其它的HTTP请求一样,用于构建 web 页面。然后由于它是动态的,人们常常忽略了缓存它的好处。
确保你的 ajax 请求遵循高性能指导方针,尤其是要有一个设置未来过期时间的Expires头。
Ajax 的缓存机制和浏览器处理资源时的缓存机制是一样的。
三条简单规则:
(1)只要是 URL 相同的 GET 请求,浏览器会使用缓存(当然还要看服务器的 Cache-Control/Expires/Last-Modified/ETag 头的设置)。
(2)只要是 POST 请求,浏览器都不会缓存。
(3)Https 的请求,浏览器不会缓存。
References
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论