New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浏览器缓存篇 #24

Open
laizimo opened this Issue Sep 6, 2017 · 4 comments

Comments

Projects
None yet
4 participants
@laizimo
Copy link
Owner

laizimo commented Sep 6, 2017

前言

在前端开发中,缓存有利于加快网页的加载速度,同时缓存能够被反复利用,所以可以减少流量和带宽的开销。

缓存的分类有很多种,CDN缓存、数据库缓存、代理服务器缓存和浏览器缓存。本篇将来讲解一下Web开发中的浏览器缓存。这个在实际开发环境中往往也会被问到,或者使用到。如何去准确认清楚缓存的概念,是前端必须要去学习的。如果你喜欢我的文章,欢迎评论,欢迎Star~。欢迎关注我的github博客

正文

浏览器的缓存问题,主要指的是http的缓存——即协议层。而h5新增的storage和数据库缓存,那是应用层缓存,并不被计入本篇的分析内容里面。下面我们正式开始来进行缓存的分析。

协议层的缓存,其实,可以被分成强制缓存和对比缓存。

强制缓存

首先,我们先来看一张强制缓存时的时序图,来了解一下强制缓存在不同情况下的请求模式:

force cache

从图中,我们不难看出,只有当缓存失效时,才会去服务器获取最新资源的方式,就是强制缓存。而在协议层的字段中,可以造成强制缓存的字段有两个Expires和Cache-Control。

1.0的时候见到我——Expires

最早使用的是Expires字段,该字段表示缓存到期时间,即有效时间+当时服务器的时间,然后将这个时间设置在header中返回给服务器。因此,该时间是一个绝对时间,举例说明:

Expires: Thu, 10 Nov 2017 08:45:11 GMT

图片示例:

expires

在响应消息头中,设置这个字段之后,就可以告诉浏览器,在未过期之前不需要再次请求。

但是,这个字段设置时有缺点

由于是绝对时间,用户可能会将客户端本地的时间进行修改,而导致浏览器判断缓存失效,重新请求该资源,同时,还导致客户端与服务端的时间不一致,致使缓存失效。

1.1的时候我来了——Cache-Control

已知Expires的缺点之后,在HTTP/1.1中,增加了一个字段Cache-Control,该字段表示资源缓存的最大有效时间,在该时间内,客户端不需要向服务器发送请求

这两者的区别就是前者是绝对时间,而后者是相对时间。我们不妨举个例子来说明一下:

Cache-Control: max-age=2592000

图片示例:

Cache-Control

下面列举一下Cache-Control的字段可以带的值:

  1. max-age:即最大有效时间,在上面的例子中我们可以看到

  2. no-cache:表示必须先与服务器确认资源是否被更改过(依据If-None-Match和Etag),然后再决定是否使用本地缓存

  3. s-maxage:同max-age,但是仅用于共享缓存,如CDN缓存

  4. public:多用户共享缓存,默认设置

  5. private:不能够多用户共享,HTTP认证之后,字段会自动转换成private。

总结一下,自从http1.1开始,Expires逐渐被Cache-Control取代。Cache-Control是一个相对时间,即使客户端时间发生改变,相对时间也不会随之改变,这样可以保持服务器和客户端的时间一致性。而且Cache-Control的可配置性比较强大。

对比缓存

扯完强制缓存,我们来看看对比缓存。在解释这个之前,是否可以先猜想一下,强制缓存是,缓存在未过有效期时,不需要请求资源。那么,对比缓存的原理又该如何呢?

废话不多说,我们也先从对比缓存的时序图讲起,如图:

compare cache

对比缓存的过程是,先从缓存中获取对应的数据标识,然后向服务器发送请求,确认数据是否更新,如果更新,则返回新数据和新缓存;反之,则返回304状态码,告知客户端缓存未更新,可继续使用。

这正好弥补了一些强制缓存的缺陷。对比缓存主要应用于一些时常需要动态更新的资源文件。

对比缓存在协议里的字段是Last-Modified和If-Modified-Since。

别人的好伙伴——Last-Modified

Last-Modified:服务器告知客户端,资源最后一次被修改的时间,例如

Last-Modified: Thu, 10 Nov 2015 08:45:11 GMT

last-modified

If-Modified-Since:再次请求时,请求头中带有该字段,服务器会将If-Modified-Since的值与Last-Modified字段进行对比,如果相等,则表示未修改,响应304;反之,则表示修改了,响应200状态码,返回数据。

这个字段可以和Cache-Control配合使用。

但是他还是有一定缺陷的:

  1. 如果资源更新的速度是秒以下单位,那么该缓存是不能被使用的,因为它的时间单位最低是秒。

  2. 如果文件是通过服务器动态生成的,那么该方法的更新时间永远是生成的时间,尽管文件可能没有变化,所以起不到缓存的作用。

我来完善它——Etag

由于Last-modified还是存在缺陷的,尽管大多数情况下,会使用它,但当遇到我们上面所说的场景时,我们可能就需要了解一下,我们另一个小伙伴了——Etag。

Etag存储的是文件的特殊标识(一般都是hash生成的),服务器存储着文件的Etag字段,可以在与每次客户端传送If-no-match的字段进行比较,如果相等,则表示未修改,响应304;反之,则表示已修改,响应200状态码,返回数据。

最后,通过一张原理图,我们来加深一下记忆:

etag

至此为止,两种缓存类型的缓存方式已经阐述完成了,不知你是否已经心中已经有个大致的印象,当别人问起时,你可以对答如流。希望我们一同进步吧,fighting。

浏览器行为引起的不同

最后,我们来聊聊浏览器行为会引起缓存的变化吧。

下面说一下浏览器的行为会产生怎样的请求:

  1. 刷新网页 => 如果缓存没有失效,浏览器会直接使用缓存;反之,则向服务器请求数据
  2. 手动刷新(F5) => 浏览器会认为缓存失效,在请求服务器时加上Cache-Control: max-age=0字段,然后询问服务器数据是否更新。
  3. 强制刷新(Ctrl + F5) => 浏览器会直接忽略缓存,在请求服务器时加上Cache-Control: no-cache字段,然后重新向服务器拉取文件。

移动端的缓存处理

在PC端或许这样子的缓存机制就已经足够了,因为PC端不需要为网络的问题担心。

但是,移动端却不行,任何一个网络请求的增加,对于移动端的加载消耗时间都是比较大的(谁叫移动端的网太差呢,3G、2G)。那么,上述的缓存有什么问题呢?其实,强制缓存是没有太大问题的,因为只要缓存不到期,是不会想服务器发送请求的;但是如果是对比缓存的情况下,304的问题就比较巨大,因为它会造成无用的请求。每次在使用缓存前,都会向服务器发送请求确认,导致网络的延时。

一次完美的缓存必须保证两点:

  1. 数据缓存之后,尽量减少服务器的请求
  2. 如果资源更新的话,必须使得客户端的资源一起更新。

所以,一般我们会运用的方式是:

在资源文件后面加上表示,如config.f1ec3.js、config.v1.js之类的,然后给资源设置较长的缓存时间,如一年

Cache-Control: max-age=31536000

这样子,就不会造成304的回包现象。
然后一旦资源发生更新时,我们可以改变资源后面的标识符,实现静态资源非覆盖式更新。

总结

本篇大致分析了浏览器缓存部分的分类情况,以及细化分析。主要可分为:

  1. 强制缓存

    • Expires字段

    • Cache-Control字段

  2. 对比缓存

    • Last-Modefied字段

    • Etag标识

  3. 浏览器行为引起的缓存变化

  4. 移动端的缓存策略

其实,在讲述移动端的缓存策略时,并没有分析的特别详细,只是大致的讲解了一下目前大家都在使用的缓存策略。可能之后,还会写一篇移动端缓存的细分文章。

最后,如果你对我写的有疑问,可以与我讨论。如果我写的有错误,欢迎指正。你喜欢我的博客,请给我关注Star~呦。大家一起总结一起进步。欢迎关注我的github博客

@laizimo

This comment has been minimized.

@laizimo laizimo changed the title h5 缓存篇 浏览器缓存篇 Sep 6, 2017

@zhangweigong

This comment has been minimized.

Copy link

zhangweigong commented Sep 20, 2017

讲的蛮通俗易懂的,解除了我很多迷惑,谢谢

@axuebin

This comment has been minimized.

Copy link

axuebin commented Oct 16, 2017

学习了

@gujindv

This comment has been minimized.

Copy link

gujindv commented Dec 4, 2018

图片挂了啊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment