浏览器缓存原理以及本地存储

作为一名前端工作人员,前端的缓存知识是必须掌握的,因为一个网站打开网页的速度直接关系到用户体验,用户粘度,而提高网页的打开速度有很多方面需要优化,其中比较重要的一点就是利用好缓存,缓存文件可以重复利用,还可以减少带宽,降低网络负荷。

1 缓存

缓存从宏观上分为私有缓存和共享缓存,共享缓存就是那些能被各级代理缓存的缓存。私有缓存就是用户专享的,各级代理不能缓存的缓存。

缓存从微观上可以分为以下几类:

  • 浏览器缓存
  • 代理服务器缓存
  • CDN缓存
  • 数据库缓存
  • 应用层缓存

这里主要对浏览器的缓存进行说明:

clipboard.png

2 http缓存

2.1 强缓存

  • 不会向服务器发送请求,直接从缓存中读取资源
  • 请求返回200的状态码
  • 在chrome控制台的network选项中可以看到size显示from disk cache或from memory cache。
from memory cache代表使用内存中的缓存,from disk cache则代表使用的是硬盘中的缓存,浏览器读取缓存的顺序为memory –> disk。在浏览器中,浏览器会在js和图片等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需直接从内存缓存中读取(from memory cache);而css文件则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存(from disk cache)。

clipboard.png

Expires和Cache-Control两者对比:其实这两者差别不大,区别就在于 Expires 是http1.0的产物,Cache-Control是http1.1的产物,两者同时存在的话,Cache-Control优先级高于Expires

2.2 协商缓存

协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程
  • 协商缓存生效,返回304和Not Modified

clipboard.png

2.2.1 Last-Modified和If-Modified-Since

浏览器在第一次访问资源时,服务器返回资源的同时,在response header中添加 Last-Modified的header,值是这个资源在服务器上的最后修改时间,浏览器接收后缓存文件和header;

浏览器下一次请求这个资源,浏览器检测到有 Last-Modified这个header,于是添加If-Modified-Since这个header,值就是Last-Modified中的值;服务器再次收到这个资源请求,会根据 If-Modified-Since 中的值与服务器中这个资源的最后修改时间对比,如果没有变化,返回304和空的响应体,直接从缓存读取,如果If-Modified-Since的时间小于服务器中这个资源的最后修改时间,说明文件有更新,于是返回新的资源文件和200

缺点:1、某些服务端不能获取精确的修改时间 2、文件修改时间改了,但文件内容却没有变

2.2.2 ETag和If-None-Match

Etag是上一次加载资源时,服务器返回的response header,是对该资源的一种唯一标识,只要资源有变化,Etag就会重新生成。浏览器在下一次加载资源向服务器发送请求时,会将上一次返回的Etag值放到request header里的If-None-Match里,服务器只需要比较客户端传来的If-None-Match跟自己服务器上该资源的ETag是否一致,就能很好地判断资源相对客户端而言是否被修改过了。如果服务器发现ETag匹配不上,那么直接以常规GET 200回包形式将新的资源(当然也包括了新的ETag)发给客户端;如果ETag是一致的,则直接返回304知会客户端直接使用本地缓存即可。

2.2.3 协商缓存两种方式的对比

  1. 首先在精确度上,Etag要优于Last-Modified,Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag每次都会改变确保了精度;如果是负载均衡的服务器,各个服务器生成的Last-Modified也有可能不一致。
  2. 性能上,Etag要逊于Last-Modified,毕竟Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值。
  3. 优先级上,服务器校验优先考虑Etag

3 缓存机制

appcache优先于强缓存,强制缓存优先于协商缓存进行,若强制缓存(Expires和Cache-Control)生效则直接使用缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,返回200,重新返回资源和缓存标识,再存入浏览器缓存中;生效则返回304,继续使用缓存。具体流程看下图:

clipboard.png

不管是浏览器缓存,还是代理服务器缓存,CDN缓存都遵循客户端与服务端之间的缓存机制

4、本地存储

本地存储主要有以下几种,localStorage,sessionStorage和cookie,WebSql和IndexDB主要用在前端有大容量存储需求的页面上,例如,在线编辑浏览器或者网页邮箱。他们都可以将数据存储在浏览器,应该根据不同的场景进行使用。

4.1 Cookie

Cookie主要是由服务器生成,且前端也可以设置,保存在客户端本地的一个文件,通过response响应头的set-Cookie字段进行设置,且Cookie的内容自动在请求的时候被传递给服务器。如下:

[HTTP/1.1 200 OK]
Server:[bfe/1.0.8.18]
Etag:["58860415-98b"]
Cache-Control:[private, no-cache, no-store, proxy-revalidate, no-transform]
Connection:[Keep-Alive]
Set-Cookie:[BDORZ=27315; max-age=86400; domain=.baidu.com; path=/]
Pragma:[no-cache]
Last-Modified:[Mon, 23 Jan 2017 13:24:37 GMT]
Content-Length:[2443]
Date:[Mon, 09 Apr 2018 09:59:06 GMT]
Content-Type:[text/html]

Cookie包含的信息:
它可以记录你的用户ID、密码、浏览过的网页、停留的时间等信息。当你再次来到该网站时,网站通过读取Cookies,得知你的相关信息,就可以做出相应的动作,如在页面显示欢迎你的标语,或者让你不用输入ID、密码就直接登录等等。一个网站只能读取它自己放置的信息,不能读取其他网站的Cookie文件。因此,Cookie文件还保存了host属性,即网站的域名或ip。
这些属性以名值对的方式进行保存,为了安全,它的内容大多进行了加密处理。Cookie文件的命名格式是:用户名@网站地址[数字].txt

Cookie的优点:

  • 给用户更人性化的使用体验,如记住“密码功能”、老用户登录欢迎语
  • 弥补了HTTP无连接特性
  • 站点统计访问人数的一个依据

Cookie的缺点:

  • 它无法解决多人共用一台电脑的问题,带来了不安全因素
  • Cookie文件容易被误删除
  • 一人使用多台电脑
  • Cookies欺骗。修改host文件,可以非法访问目标站点的Cookie
  • 容量有限制,不能超过4kb
  • 在请求头上带着数据安全性差

4.2 localStorage

localStorage主要是前端开发人员,在前端设置,一旦数据保存在本地后,就可以避免再向服务器请求数据,因此减少不必要的数据请求,减少数据在浏览器和服务器间不必要地来回传递。

可以长期存储数据,没有时间限制,一天,一年,两年甚至更长,数据都可以使用。
localStorage中一般浏览器支持的是5M大小,这个在不同的浏览器中localStorage会有所不同

优点:

  • localStorage拓展了cookie的4k限制
  • localStorage可以将第一次请求的5M大小数据直接存储到本地,相比于cookie可以节约带宽
  • localStorage的使用也是遵循同源策略的,所以不同的网站直接是不能共用相同的localStorage

缺点:

  • 需要手动删除,否则长期存在
  • 浏览器大小不一,版本的支持也不一样
  • localStorage只支持string类型的存储,JSON对象需要转换
  • localStorage本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡

4.3 sessionStorage

sessionStorage主要是前端开发人员,在前端设置,sessionStorage(会话存储),只有在浏览器被关闭之前使用,创建另一个页面时同意可以使用,关闭浏览器之后数据就会消失

存储上限限制:不同的浏览器存储的上限也不一样,但大多数浏览器把上限限制在5MB以下

4.4 websql

Web SQL 是在浏览器上模拟数据库,可以使用JS来操作SQL完成对数据的读写。它使用 SQL 来操纵客户端数据库的 API,这些 API 是异步的,规范中使用的方言是SQLlite。数据库还是在服务端,不建议使用,已废弃

4.5 indexDB

随着浏览器的功能不断增强,越来越多的网站开始考虑,将大量数据储存在客户端,这样可以减少从服务器获取数据,直接从本地获取数据。

现有的浏览器数据储存方案,都不适合储存大量数据:Cookie 的大小不超过4KB,且每次请求都会发送回服务器;LocalStorage 在 2.5MB 到 10MB 之间(各家浏览器不同),而且不提供搜索功能,不能建立自定义的索引。所以,需要一种新的解决方案,这就是 IndexedDB 诞生的背景。

通俗地说,IndexedDB 就是浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。这些都是 LocalStorage 所不具备的。就数据库类型而言,IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。

关于indexDB的知识可以查看这篇文章http://www.ruanyifeng.com/blo...

这里,我只是根据自己的理解整理了一下关于缓存,存储方面的知识,还有很多不足的地方,更多实践的知识,还请查看其他文章,如有错误,请指出

参考文章:
https://www.jianshu.com/p/54c...
https://segmentfault.com/a/11...
http://www.cnblogs.com/etoah/...
https://blog.csdn.net/zhouche...


更多专业前端知识,请上 【猿2048】www.mk2048.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/366217.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux shell 宏定义_linux内核修炼之系统调用

fork()这个系统调用是有两个返回值的,在子进程中的返回值是0,在父进程中的返回值是PID,如下图 fork一次 返回两次关于0x80中断和特权级检查在mian函数的sched_init()函数中调用宏:set_system_gate(0x80,&system_call);将0x80号…

使用JPA和Hibernate有效删除数据

您可能会遇到必须对关系数据库中存储的大量数据集执行批量删除的情况。 如果您将JPA与Hibernate一起用作基础OR映射器,则可以尝试通过以下方式调用EntityManager的remove()方法: public void removeById(long id) {RootEntity ro…

java21个知识点重点_java21个知识点重点

http://blog.csdn.net/jerroluo/article/details/520025851. JVM相关(包括了各个版本的特性)对于刚刚接触Java的人来说,JVM相关的知识不一定需要理解很深,对此里面的概念有一些简单的了解即可。不过对于一个有着3年以上Java经验的资深开发者来说&#xf…

Django模型中字段属性choice使用

今天设计models时,用到了choice这个属性,用来限制用户做出选择的范围。比如说性别的选择(男或女)。 class User(AbstractUser):。。。sex models.CharField(verbose_name性别,max_length5,choi…

面试题4,打印出100-999所有的“水仙花数”。

提示:水仙花数是指一个 n 位数 ( n≥3 ),它的每个位上的数字的 n 次幂之和等于它本身。 (例如:1^3 5^3 3^3 153) package 面试;/*** 水仙花数* author liugang* create 2018/12/19 20:07**/ public class Shuixianhu…

angularjs的$http请求方式

/*$http常用的几个参数$http服务的设置对象:1、method 字符串 表示发送的请求类型 get post jsonp等等2、url 字符串 绝对或者相对的URL,请求的目标3、params 字符串或对象 会被转化成查询字符串加到URL后面,如果不是字符串会被JSON序列化4、data 字符串或者对象 这…

response对象设置返回状态_postman 设置全局变量

postman大家都知道是一个测试接口的工具,也是目前比较流行的一种测试工具,但是postman只是用来将API地址和参数填入send一下就完了吗?其实不是,关于postman其实有很多玩法,对于测试来说我觉得掌握了postman是非常有必要…

测试过大输入的代码

在编写单元测试时,我们主要关注业务的正确性。 我们将竭尽所能,开开心心地走在最前沿。 我们有时会进行微基准测试并衡量吞吐量。 但是经常遗漏的一个方面是当输入过大时我们的代码如何表现? 我们测试了如何处理正常的输入文件,格…

资源不在java项目和构建路径上_编译单元不在Java项目的构建路径上-Maven

今天,我已经在日食中导入了一个Maven项目.当我尝试自动建议时,当我添加一些代码时,它提示我“编译单元不在Java项目的构建路径上”.我没有看到解决此问题的方法,但是都没有解决.这个应该做什么?xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://m…

Django 第八课 2.【MySQL相关软件 mysqlclient Navicat Premium】

MySQL 驱动程序安装: 我们使用 Django 来操作 MySQL,实际上底层还是通过 Python来操作的。因此我们想要用 Django 来操作 MySQL,首先还是需要安装一个驱动程序。在python3中,驱动程序有多种选择。比如pymysql 以及mysqlclient等。…

查看串口的驱动信息

1、查看串口的驱动信息 2、驱动安装文件:http://www.wch.cn/download/CH341SER_EXE.html 3、参考驱动资料:https://blog.csdn.net/jazzsoldier/article/details/70169732 转载于:https://www.cnblogs.com/qy1234/p/10146303.html

用jQuery监听浏览器窗口的变化

1 $(window).resize(function () { //当浏览器大小变化时 2 alert($(window).height()); //浏览器时下窗口可视区域高度 3 alert($(document).height()); //浏览器时下窗口文档的高度 4 alert($(document.body).height()); //浏览器时下…

java中怎么判断一段代码时线程安全还是非线程安全_Java 中的多线程你只要看这一篇就够了...

引如果对什么是线程、什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内。用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现。说这个话其实只有一半对,因…

使用Maven设置您的应用服务器

在许多情况下,无需先设置应用程序就无法部署应用程序。 在JBoss AS 7.x中,您可能需要配置例如数据库连接。 或者,您必须配置一个安全领域。 也许您还想调整SLSB池…在任何一种情况下,团队中的所有开发人员都必须共享一个共同的或至…

[洛谷P3178][HAOI2015]树上操作

题目大意:有一棵点数为 $N$ 的树,以点 1 为根。然后有 $M$ 个操作。 1. 把 $x$ 的点权增加 $a$ 。 2. 把 $x$ 为根的子树中所有点的点权都增加 $a$ 。 3. 询问 $x$ 到根的路径中所有点的点权和。 题解:树链剖分模板题 卡点:我真的…

实现 通过数据库里一个字段值相等 则把 他合为一条数据

需求: 把红色合为一条数据,绿色合为一条数据 结果: 不多说直接上代码......................................................... // 先查所有数据 const goods await service.goods.findAllGoodsWithParams({where: params,offset: ctx.p…

CSS定义字体间距 字体行与行间距

1 2     letter-spacing:像素(字母或中文字的左右间距)3 4 word-spacing:像素(两个单词之间的左右间距)5 6 line-height:像素(两行之间的间距)7 8 text-decoration:字体的装饰&am…

float与double类型参数区别_8大基本数据类型及包装类,不知道这些点别说自己是大佬...

一般地,当需要使用数字的时候,我们通常使用内置数据类型,如:byte、int、long、double 等。然而,在实际开发过程中,我们经常会遇到需要使用对象,而不是内置数据类型的情形。为了解决这个问题&…

宣布EAXY:在Java中简化XML

Java中的XML库是一个雷区。 操作和读取XML所需的代码量令人震惊,使用不同的库遇到类路径问题的风险很大,并且命名空间的处理带来了很多混乱和错误。 最糟糕的是,情况似乎并没有改善。 一位同事让我意识到JOOX库。 这是解决这些问题的一个很好…

9-客户端集成IdentityServer

1-创建客户端的webapi项目 E:\coding\netcore\IdentityServerSample>dotnet new webapi --name IdentityCredentialApi 2-在需要启用授权的方法上增加Authorize标签 3-使用nuget工具安装 IdentityServer4.AccessTokenValidation 4-启用客户端授权, 需要配置连接…