admin管理员组

文章数量:1530085

论提升人机交互设计体验之-浏览器Disk Cache磁盘缓存及其协商缓存、及原生App和浏览器实现缓存的差异

目录

论提升人机交互设计体验之-浏览器Disk Cache磁盘缓存及其协商缓存、及原生App和浏览器实现缓存的差异

1、Memory Cache和Disk Cache区别

1.1、Memory Cache

1.2、Disk Cache

1.2.1、Disk Cache的存取举例

1.2.2、Disk Cache的存取方式

2、缓存,按执行优先级次序分类

2.1、浏览器存储的自身行为

2.2、Service Worker

2.3、Memory Cache

2.4、Disk Cache(与http指令的cache匹配,故又名Http Cache)

2.5、Push Cache

3、Disk Cache缓存,按其功能的类型分类

3.1、强制缓存

3.2、协商缓存

    3.2.1、当被浏览器“强制缓存”的资源,在服务端发生“Modified”改变时,浏览器这一侧,缓存将如何“更新”;

    3.2.2、当被浏览器“强制缓存”的资源,在服务端是否可以给定一个“过期”的机制,过期后,浏览器这一侧,该如何处理,且如何如何“更新”缓存;

    3.2.3、浏览器的“导航器”或“浏览器的内置js解释器引擎”,首次处理H5或Http请求的资源时,应当采用什么样的机制。

4、浏览器实现请求网络超大文件的本机存储的策略

4.1、针对非IndexDB的存储

4.2、使用IndexedDB存储

4.3、使用H5原生的serviceWorker技术

5、原生App和浏览器实现本机存储和缓存的差异


        运用好“缓存”,可以充分利用浏览器的一些特性,尽最大可能地提升人机交互设计体验。否则,用户的交互体验可能会非常糟糕。

        我们知道,在计算机中,数据存储,要么读写“内存”、要么读写“ 磁盘”,没有第三者。浏览器也不例外,其存取数据,要么读写“内存”、要么读写“磁盘”,也没有第三者。

        “缓存”的目的:

        无论是web应用,还是原生App应用,无论是在客户端,还是在服务端,应用为了提升执行的效率(体现时间、速度)和节省设备和网络的关键性能指标(比如网络带宽的开销、CPU利用率、内存耗用、硬盘读写的I/O负载)的开销,会考虑将一些“请求”的资源在“内存”中或在“磁盘”中“预备”好,需要的时候,直接提取出来使用,从而减少了:

        网络的往返的次数;

        数据的重复计算;

        数据的重复提取;

        数据量的大小。

        浏览器“缓存”的目的:

◆  首先:应当考虑上述“通用”的“缓存”目的;

◆  其次:是缓解浏览器自身来自“内存”读写的负载的。浏览器内部的“内存管理模块”,会尽可能的使用高速内存以提高效率,当其内部代码逻辑,发现本机内存已吃紧,它会自动启用对“磁盘”储存来进行读写,“磁盘”储存即我们通常所说的“虚拟内存”。

◆  浏览器利用本机的“虚拟内存”:是操作系统提供的外部存储,用以扩展“内存”的使用,因为它本质上并不是真正的“内存”,所以称为“虚拟”;它是“硬盘”上的“分块”的页面文件,MsWindows的话,将其作为“ROM”来进行使用;“虚拟内存”的速度取决于磁盘I/O,其性能远低于“内存”的I/O。

◆  浏览器为了简化用户对上述对其内部“对外公开”的“内存”管理功能和“虚拟内存”功能的“引用”,按照www组织的定义,对暴露给用户的“存储”及其关联的“缓存”的概念、分类、功能和用法,进行了进一步的“划分”:

    ◇  “Service Worker方式的(即PWA的实现的基础)”Cache Storage:

https://developer.chrome/docs/devtools/progressive-web-apps/?utm_source=devtools#opaque-responses

    ◇  “非Service Worker方式的”Cache Storage:

        本文实际测试一下浏览器的行为、浏览器的存储、与存储关联的“缓存”。

1、Memory Cache和Disk Cache区别

1.1、Memory Cache

◆浏览器自动的性能行为

◆存储位置:内存的地址及其空间

◆时效性:导航器刷新或浏览器关闭,即刻释放

1.2、Disk Cache

◆总是与Http的“请求-响应”相关

◆存储位置:磁盘中不同类型的存储路径

◆时效性:导航器刷新或浏览器关闭,不受影响

1.2.1、Disk Cache的存取举例

        拿MSWindows来举例(不同OS操作系统平台,各异:包括各派别的手机操作系统、各服务器操作系统厂家或发起机构、各PC操作系统厂家或发起机构),存储位置:

        我们知道,所有MSWindows应用,其统一的本机“用户数据”的存取路径,均为:

C:\Users\Administrator\AppData\Local\

(除非你修改了操作系统默认的“全局路径”)

        现以\Google\Chrome浏览器的\User Data用户数据,默认的Local Storage加密数据举例:

C:\Users\Administrator\AppData\Local\Google\Chrome\User Data\Default\Local Storage\leveldb

        它对应了浏览器控制台该位置的数据存取:

(图2) 

        除此之外,还有各种本机用户的应用的默认数据:

(图3) 

        “Disk缓存”就是上述的其中一类“用户数据”。

1.2.2、Disk Cache的存取方式

◆要么“用户”与“浏览器”的控制台“交互”(如图2);

◆要么以编程的方式:动态地请求其中的数据,可以是与浏览器相关的API的方式、可以是浏览器原生SDK软件开发包或IDE厂家对SDK编制的API的方式。但,均需受制于必要的“源”的“权限机制”或“征得所有者(用户)的许可”(如图2或图3)。

◆默认是按“源/域”进行分区的

2、缓存,按执行优先级次序分类

◆浏览器的存储about:blank

◆Service Worker

◆Memory Cache

◆Disk Cache(与http的指令cache匹配,故又名Http Cache)

◆Push Cache

◆......等等,其它缓存

        现,分别概述一下: 

2.1、浏览器存储的自身行为

        当“导航器”中首次执行输入的Location的URL地址时,会强制触发Storage下的第一方和第三方的"域/源"、(如果有的话,同时会读写:)及其“Cookies”、“IndexedDB”:

◇Loacal Storage

◇Session Storage

◇Cookies

        典型的引用,比如我们用导航器打开“腾讯云”的站点:https://cloud.tencent/

2.2、Service Worker

        MsWindows下,其物理存取路径为:

C:\Users\Administrator\AppData\Local\Google\Chrome\User Data\Default\Service Worker

        按照其Disk Cache缓存内容的不同,分别可以对这些“缓存位置”及其“缓存内容”,进行存取:

         其结构如下:

        需要注意的是,这个存储大小的配额数值:指的是:

        如果使用了service worker并进行了addResourcesToCache缓存操作,在service worker模式下对cache storage的配额是没有限制的。仅仅在:在“非service worker环境”下,在没有使用indexedDB时,单次请求、单个文件的存储,不超过7m/个文件/次请求;

         那么,在“非service worker环境”下,超了怎么办?我们应当使用技巧:就是在请求时,将大文件chunk分块成N多个小块文件,每个文件不超过阀值(7M,安全起见,均设置为5M,与普通非SW缓存的使用保持一致);在服务端一次性生成这些文件,客户端一次请求N多个chunked分块。

        典型的应用情景,就是“分页”数据的“静默”提取:将“渲染主线程上下文”中所需的“每个分页”数据,在“非渲染主线程上下文”(SW的安全上下文)中一次性地全部分别fetch下来,保存到Cache Storage中,以便“渲染主进程window”中的"worker"(负责渲染的网页)根据需要,从缓存中读取。但是你会发现,如果1个59MB的Json文件,你下载会非常的耗时,而且它被一次性地渲染布局到页面中也会有“卡顿”发生,那么怎么办呢:就是采用上述办法,请求N多个chunked分块,服务端一次性生成这些文件,让“每个分页”只渲染和布局绘制1个chunked分块,这样在Cache Storage体现出来就是所有N个Json文件(每个chunked分片的Json文件大小 = 59MB/N <=5MB),Cache Storage中缓存的“每个Json文件”为“每个分页”提供本机的数据服务。

        刷新或再次使用该“资源”,0KB,从磁盘缓存中提取,不再消耗网络和服务器时间(但是本机渲染和布局绘制的时间,仍旧是独立的,需要单独消耗的): 

        同理,利用“缓存更新技术”:可以比较Cache Storage中存储的数据,和服务端存取的数据,之间的“字节差异”,做客户端的“缓存更新一次性提交客户端维护的变化了的数据”。

◆ SW的Disk Cache:“默认”,是按“源/域”进行分区的,而且是按“顶级文档源”(地址栏中显示的来源);

◆ 当然:你也可以使用“不透明响应”,来绕过这种限制,来实现“跨域安全策略”;

◆ SW:也可以使用IndexedDB存储。

        SW,现已被绝大多数浏览器内核,接受并支持,只有少数不支持(注意,不要将PWA和SW划等号,PWA需要依赖SW的技术而已),下图是iPhone 7下iOS 13.6的效果:

◆ 苹果的态度:

        从2018年起,Safari Technology Preview 48、macOS High Sierra 10.13.4 beta seed 2 和 iOS 11.3 beta seed 2及其之后,苹果便开始了对serviceWorker的支持和发布。
◆ 苹果对待serviceWorker的观点:

        Service Worker API是在 WebKit 的多进程基础架构中实现的,它提供了安全性和性能优势。
◆ serviceWorker的启动运行和停止运行的机制:

        由于 Service Worker 实例同时消耗内存和 CPU 时间,因此仅在需要时运行它们很重要。serviceWorker通常在最初由网页注册时启动。在正常情况下,当一个serviceWorker的分区中没有serviceWorker的客户端,在一个小的宽限期后,serviceWorker将被终止。每当需要一些交互时,serviceWorker都会重新启动。
◆ serviceWorker与存储和缓存:

        serviceWorker和缓存API存储的信息将随着用户浏览内容而增长。为了只保留对用户有用的存储信息,WebKit 将在几周后(或苹果最新政策规定的时间期限)删除未使用的serviceWorker注册。几周后未打开的缓存也将被删除。Web 应用程序必须对任何被删除的单个缓存、缓存条目或serviceWorker具有弹性。
◆ 苹果Safari浏览器支持对serviceWorker的代码调试debug:
        苹果Safari浏览器的Web Inspector 支持调试serviceWorker(若是手机的话,需要手机usb与macOS电脑连调)。“开发”菜单中包含随时运行的serviceWorker列表。单击其中一个 service worker 条目的js时,将附加一个检查员到该serviceWorker。从这里,可以使用断点调试与 fetch 或 postMessage 事件相关的代码。检查器控制台也是使用 fetch API 在serviceWorker上下文中触发网络负载的好地方。也可以通过几行代码从控制台检查 service worker 缓存,比如: 

// # 在各个平台通用的调测代码:
await fetch('_index.html')
await self.caches.keys()
cache = await self.caches.open('v1')
await cache.keys()
await cache.matchAll()

        iOS在https下支持SW,下图为安装状态:

         下图为已激活状态:

          但是iOS在http下不支持SW(理论上,所有平台SW都应当在https或安全上下文中作业),下图为提示状态:

          总之,一句话,移动端,无论原生App也好、web应用也好,不同平台及其内置浏览器会有许多限制,我是将开发选项中很多,都打开了的;或者通过代码请求权限,拉起提示让“用户”授权:

  

         检测支持情况,官方推荐站点1:

         检测支持情况,官方推荐站点2:

Is service worker ready?

2.3、Memory Cache

        通常,浏览器的导航器,在初次执行window.location的URL时,或重复刷新页面时,会考虑将如下资源优先进行“内存缓存Memory Cache”:

◆html的DOM解构:

        优先级,最高,用于渲染、元素本身不缓存:

◆head中的:

        优先级,最高:

        ◇除icon类型的(包括x-icon)以外的<link>资源,特别是style样式表的css文件;

        icon类型的<link>资源---属于特殊类型,为Disk Cache(优先级:最高)

◆body中的:

        ◇页面中直接使用H5原生的fetch的src="路径"的资源,比如:

        优先级(js文件或嵌入script中的js代码)中等:

<script src="../js/index.js"></script>

        优先级(img、音视频类)低:

<img src="../img/test.png" alt="">等,再比如:

2.4、Disk Cache(与http指令的cache匹配,故又名Http Cache)

        再次执行同样URL的导航window.location,或再次刷新页面,之前的“内存缓存Memory Cache”,将被”强制缓存“至"Disk Cache磁盘缓存"中,并且此时服务端若存在304协商机制的代码,同时"协商缓存"会生效,将其Etag唯一性缓存标识及缓存的Cache-Control过期控制信息返回给浏览器的"Disk Cache磁盘缓存"。

2.5、Push Cache

        Push Cache与浏览器的“后端服务”代码相关:

3、Disk Cache缓存,按其功能的类型分类

◆强制缓存

◆协商缓存

3.1、强制缓存

        当导航器或http请求,首次执行时,浏览器为了“性能”,首次强行的“缓存”至内存,再次执行相同URL请求时,浏览器“强制缓存”至磁盘。总之,“强制缓存”,是浏览器干出来的,与http和网络,原本并无干系

3.2、协商缓存

        由于浏览器永远都期望强行的进行本机的“缓存”,那么当“资源变化”时,若它也“强制缓存”,那么必然会导致代码与视觉或数据之间“不符合逻辑”,怎么办呢?

        代表App的浏览器的厂商,与代表代码的js、html和css的阵营和为html而生的http,它们之间坐下来商议,我们需要出一个“标准”:

    为了共同的“性能”的目标,我们之间(浏览器和后端服务代码)需要明确几点:

    3.2.1、当被浏览器“强制缓存”的资源,在服务端发生“Modified”改变时,浏览器这一侧,缓存将如何“更新”;

    3.2.2、当被浏览器“强制缓存”的资源,在服务端是否可以给定一个“过期”的机制,过期后,浏览器这一侧,该如何处理,且如何如何“更新”缓存;

    3.2.3、浏览器的“导航器”或“浏览器的内置js解释器引擎”,首次处理H5或Http请求的资源时,应当采用什么样的机制。

        于是,代表这种“提议”的“标准”出来了,即rfc 2616中的“10.3.5 304 Not Modified”及其“关联标准”条目:

◆  If the client has performed a conditional GET request and access is

allowed, but the document has not been modified, the server SHOULD

respond with this status code. The 304 response MUST NOT contain a

message-body, and thus is always terminated by the first empty line

after the header fields.

如果客户端已执行条件GET请求,并且访问是允许的,

但文档还尚未被修改话,服务器应用此状态码进行响应。

304响应不得包含 消息正文message-body,

因此总是在标题字段header fields之后以第一个空行结束first empty line。

◆  The response MUST include the following header fields:

响应必须包括以下标题字段header fields:

◆  - Date, unless its omission is required by section 14.18.1

-日期,除非第14.18.1节“ ClockLess Origin Server Operation无时钟“源”服务器操作”中要求省略

◆  If a ClockLess origin server obeys these rules, and proxies and

clients add their own Date to any response received without one (as

already specified by [RFC 2068], section 14.19), caches will operate

correctly.

如果无时钟源服务器( ClockLess origin server)遵守这些规则,

代理或客户端将它们拥有的“日期Date”添加到接收到的任何没有日期的响应中

(如已由[RFC 2068]第14.19节规定),缓存将正确地运行。

◆  - ETag and/or Content-Location, if the header would have been sent

in a 200 response to the same request

-如果在对同一请求的200的响应中,标题header已经被导航器或代码执行了200 OK的发送,

则标记:ETag和/或Content Location

◆  - Expires, Cache-Control, and/or Vary, if the field-value might

differ from that sent in any previous response for the same

variant

-如果字段值与之前发送的相同响应的变量值不同,可以发送响应头:

过期Expires、缓存控制Cache-Control 和/或 更改Vary

◆  If the conditional GET used a strong cache validator (see section

13.3.3), the response SHOULD NOT include other entity-headers.

Otherwise (i.e., the conditional GET used a weak validator), the

response MUST NOT include other entity-headers; this prevents

inconsistencies between cached entity-bodies and updated headers.

如果条件GET使用了“强制缓存”验证器strong cache validator(请参阅第节13.3.3),

响应不应包括其他实体标头entity-headers。

否则(比如:条件GET使用“弱”验证器weak validator)响应不得包含其他实体标头;

这可以防止“缓存的实体主体cached entity-bodies”和“更新的标头updated headers”之间的不一致。

◆  If a 304 response indicates an entity not currently cached, then the

cache MUST disregard the response and repeat the request without the

conditional.

如果304响应指示当前实体未被缓存,则缓存必须并且是无条件地忽略响应

◆  If a cache uses a received 304 response to update a cache entry, the

cache MUST update the entry to reflect any new field values given in

the response.

如果缓存使用接收到的304响应来更新缓存条目,缓存必须更新条目以反映给定的响应中的任何新字段值。

        概括起来,“协商”三条,即为“协商缓存”:

    为了共同的“性能”和“可用性”的目标,“浏览器联盟一方”同“后端服务开发联盟和http网络一方”,一致明确了,如下的"w3c执行标准":

    3.2.1、当被浏览器“强制缓存”的资源,再次请求“相同资源”时(即请求的URL不变),无论服务端的资源的名称或字节数是否变化,均需要“在本机做验证和效验”Etag标识及其对应的Control-Cache: max-age=***毫秒,must-revalidate: true的是否过期且重新验证的信息,效验该资源是否有效或过期:若未过期,则无需重新请求“服务端”,直接使用“本机缓存”的内容加载、渲染并绘制页面;若过期或无效,则浏览器让客户端的代码,重新发起“资源的网络请求”、“在服务端做验证和效验”处理,并据此重新“更新本机的缓存”;此过程,称为“协商缓存”验证和效验;同时,若存在no-cache,或Cache-Control: max-age=0;must-revalidate:true,没有缓存或无效,也需要做相应的“协商缓存”的“在服务端做验证和效验”处理 。    

        no-store:“不要做任何缓存”,任何响应的内容都不走缓存,无论是强制缓存、还是协商缓存。

        private:默认,内容仅在UA客户端方可缓存,不能在代理服务器做缓存;
        public:默认,内容即可缓存到UA客户端,也可缓存到cdn等其它任何代理服务器。

    3.2.2、服务端对浏览器“强制缓存”的资源设定并保留一个“过期”的副本copy,同时向浏览器的响应头写入一个“Cache-Control: max-age=***秒(为了兼容IE,若不使用缓存的情景:Cache-Control:no-cache 还附加了字段Pragma: no-cache )” 的过期字段 和 一个对缓存的唯一性“标记Etag(一般为base64格式的加密字符串等格式)”;浏览器在“缓存”时用同样的“标记Etag”来做本机存储和唯一性识别;

    3.2.3、浏览器的“导航器”或“浏览器的内置js解释器引擎”,首次处理H5或Http请求的资源时:让本机代码向服务端发出xhr或fetch请求,同时将服务端的响应头的“标记Etag”和响应内容的结果,浏览器将响应消息同时写入本机“缓存”。

        既然叫“协商”,就是:需要“浏览器执行前端代码”和“后端代码”,共同作协的结果,需要“前端开发人员”和“后端开发人员”,协商确定,共同一致的处理方法。

4、浏览器实现请求网络超大文件的本机存储的策略

4.1、针对非IndexDB的存储

        首先,肯定是针对Disk Cache,无论是service worker,还是强制缓存或协商缓存;

        其次,是请求的策略上,采用分块下载(chunked):浏览器客户端这一侧用“分片下载”来与服务端“协商请求”资源,而服务端则协商后采用将超大文件的资源,切割成N块(每块<=5MB的浏览器单个文件配额)的方式send发送响应给客户端,客户端存储到响应的Disk Cache,而读取或渲染时,以可读流的方式读取到内存,进行合并,当然此方式也受制于客户端“内存”的大小,还不是真正意义上的“超大文件”储存方案。

4.2、使用IndexedDB存储

        使用IndexedDB技术,将不受制于单次请求单个文件的5MB配额的限制。理论上没有限制,IndexedDB官方并没有做特别的说明。大厂,一般采用此这种浏览器端的存储策略,比如我的博客:《大厂后台管理passportal的通行做法-之腾讯云研究》https://blog.csdn/pulledup/article/details/127488160 中,腾讯云就使用了此存储方案。  

4.3、使用H5原生的serviceWorker技术

        (如上“2.2、Service Worker”节所述,略;其中也可以结合使用IndexedDB来进行存储)。

5、原生App和浏览器实现本机存储和缓存的差异

        原生App和浏览器实现缓存的差异,首先要从本机存储的差异说起:

比较项原生App浏览器备注
本机存储的位置◆电脑端:在目录访问权限框架内不限◆浏览器自身的沙盒内的指定分类目录,分别存取不同的存储类型;并分别公开在浏览器devtool不同的分区比如Android可参考:我的博文 
◆移动端:总的,在“沙盒”内不限;细分,在沙盒内根据分类分子路径存取文件。
本机存储磁盘占用配额◆均不限◆单次请求中的单个文件:配额<=5M 
本机存储的方法◆完全取决于客户端的请求和服务端的响应,在内存和磁盘之间,相互转储◆service worker:灵活,可自主决定哪些需要存储或缓存,以及方式等 
◆非service worker方式,取决于:
  ◇ 浏览器自身的行为
  ◇ Memory Cache的存取特点
  ◇ Disk Cache的存取特点和存取的位置分类的关系
  ◇ Push Cachedeng background service的存取特点和存取位置分类的关系

        然后,在它们各自的“本机存储”的基础上,对应其缓存的读写,即可,总的来说,就是从“内存”到“磁盘”之间的相互“转储”。细节,略。

喜欢的,就收藏并点个赞,鼓励我继续技术的原创写作及经验分享:

《大厂后台管理passportal鉴权登录的通行做法-之腾讯云研究》:

https://blog.csdn/pulledup/article/details/127488160

本文标签: 缓存浏览器人机磁盘差异