图片 16

一篇小表明白Web缓存,HTML五缓存机制浅析

By admin in web前端 on 2019年5月3日

一篇文章理解Web缓存

2018/08/09 · 基础技术 ·
缓存

原文出处:
这是你的玩具车吗   

最近把前端缓存重新整理了一下,从整体的层面上把前端所有能用的缓存方案梳理了一遍。同时,对于http缓存,使用了表格的方案,使得原先晦涩难记的特性变得清晰明了。特记录于此,若有什么欠缺,也望不吝指出。

时间:2017-03-27 18:02:47

参考以下文章

1. 前端缓存概述

前端缓存主要是分为HTTP缓存和浏览器缓存。其中HTTP缓存是在HTTP请求传输时用到的缓存,主要在服务器代码上设置;而浏览器缓存则主要由前端开发在前端js上进行设置。下面会分别具体描述。

图片 1

该文章为
《HTML5缓存机制浅析:移动端Web加载性能优化》
的读书笔记,整理一下自己的收获。

注意,我们讨论的所有关于缓存资源的问题,都仅仅针对GET请求。而对于POST,
DELETE, PUT这类行为性操作通常不做任何缓存。

2. 前端缓存分类

一、HTML5缓存机制介绍

HTML5是新一代的HTML标准,加入很多新的特性。离线存储(也可称为缓存机制)是其中一个非常重要的特性。HTML5引入的离线存储,这意味着Web应用可进行缓存,并可在没有因特网连接时进行访问。

浏览器缓存==客户端缓存

图片 2浏览器请求静态资源的过程

下面这张图展示了某一网站,对不同资源的请求结果,其中可以看到有的资源直接从缓存中读取,有的资源跟服务器进行了再验证,有的资源重新从服务器端获取。

图片 3

浏览器缓存分为两种,分别是强制缓存协商缓存

2.1 HTTP缓存

整体流程:HTTP缓存都是从第二次请求开始的。
第一次请求资源时,服务器返回资源,并在respone
header头中回传资源的缓存参数;第二次请求时,浏览器判断这些请求参数,击中强缓存就直接200,否则就把请求参数加到request
header头中传给服务器,看是否击中协商缓存,击中则返回304,否则服务器会返回新的资源。

HTTP缓存分为强缓存和协议缓存,它们的区别如下:

图片 4

200 from disk or 200 from memory :
强缓存的200也有两种情况:200 from disk和200 from
memory。现在我没有找到明确的文档来描述这种区别的发生条件。知乎这个问题中提到了一些情景,可以自行取用。

1.1 HTML5应用程序缓存带来的优势

  1. 离线浏览
  2. 提高加载速度(从缓存中加载)
  3. 减少服务器负载(浏览器将只从服务器下载更新的资源,强缓存的则不发起HTTP请求,协商缓存会发起HTTP,和服务器验证文件是否修改过了)
强制缓存

浏览器在加载资源时,会根据这个资源的http请求头去看是否命中强缓存,如果命中强缓存就直接用浏览器缓存的资源,这个过程中没有发请求给服务器

2.1.1 强缓存

图片 5

1.2 现有的HTML5缓存机制

勾选的,表示熟悉

  • [x] 浏览器缓存机制(强缓存,协商缓存)
  • [x] DOM Storgage 存储机制
  • [ ] Web SQL DataBase 存储机制 【关系型数据库】
  • [ ] Application Cache (App Cache)机制
  • [ ] Indexed DataBase (IndexedDB) 【NoSQL】
  • [ ] File System API

Web SQL DataBase
官方的标准文档不在推荐使用,将来也不再维护,(2015年12月);

  • 各大桌面浏览器和移动端浏览器都有很好的实现这个接口,兼容性问题不大,底层基本都是
    sqlite(正因为这样,作为一个web标准是不可接受的)

    • 经测试,IOS上容量最大支持50M,不过用系统自带的safari,超过5MB,会主动提醒用户是否要增加数据库大小,不友好(不过微信里面不会)
    • 5MB 如果用来存一些日志,还是够的(当然需要记得清理旧的日志)
    • websql
      目前是主要的解决方案(腾讯用来做日志记录,方便排查用户的错误反馈)
  • Indexed DataBase
    是下一代的客服端结构化数据持久存储反感,目前各大浏览器中也有很好的支持,是未来用来替换
    websql 的方案。

等下查下最新的情况。

这里只是官网推荐的比较,具体使用还需要看目前业界上的情况。
比如websql目前还是主流的,indexdb是未来用来替换的,具体需要多久,还需要等等。

图片 6

协商缓存

这个过程有发请求给服务器,服务器返回304,不会返回数据,还是继续用浏览器缓存的数据。

2.1.2 协商缓存

协商缓存都是成对出现的。
图片 7

1.3 目标

  • [ ] 分析各种缓存机制的原理,用法,特点
  • [ ] Android移动端Web性能加载优化
  • [ ] 如何利用缓存机制提高Web加载性能
与强制缓存有关的两个属性

Cache-Control和Expires

  • Cache-Control是HTTP1.1中新增的响应头
  • Expires是HTTP1.0中的响应头
  • Cache-Control使用的是相对时间
  • Expires指定的是具体的过期日期而不是秒数。因为很多服务器跟客户端存在时钟不一致的情况,所以最好还是使用Cache-Control.
  • Cache-Control和Expires同时使用的话,Cache-Control会覆盖Expires

Cache-Control有什么属性

  • max-age

指定设置缓存最大的有效时间,定义的是时间长短。当浏览器向服务器发送请求后,在max-age这段时间里浏览器就不会再向服务器发送请求了。

  • public

指定响应可以在代理缓存中被缓存,于是可以被多用户共享。如果没有明确指定private,则默认为public

  • private

响应只能在私有缓存中被缓存,不能放在代理缓存上。对一些用户信息敏感的资源,通常需要设置为private。

  • no-cache

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

  • no-store

绝对禁止缓存任何资源,也就是说每次用户请求资源时,都会向服务器发送一个请求,每次都会下载完整的资源。通常用于机密性资源。

HTTP通过缓存将服务器资源的副本保留一段时间,这段时间称为新鲜度限值。这在一段时间内请求相同资源不会再通过服务器,也就是不会向服务器发起请求。HTTP协议中Cache-Control

Expires可以用来设置新鲜度的限值,前者是HTTP1.1中新增的响应头,后者是HTTP1.0中的响应头。二者所做的事时都是相同的,但由于Cache-Control使用的是相对时间,而Expires可能存在客户端与服务器端时间不一样的问题,所以我们更倾向于选择Cache-Control。

当expire和cache-control都过期了,也就是过了这个新鲜度限值了,我们这个时候就要用到协商缓存了,这个时候就要跟服务器进行验证了。

  • 如果资源发生变化,则需要取得新的资源,并在缓存中替换旧资源。
  • 如果资源没有发生变化,缓存只需要获取新的响应头,和一个新的过期时间,对缓存中的资源过期时间进行更新即可。HTTP1.1推荐使用的验证方式是If-None-Match/Etag,在HTTP1.0中则使用If-Modified-Since/Last-Modified。

2.1.3 最佳优化策略-消灭304

最佳优化策略:因为协商缓存本身也有http请求的损耗,所以最佳优化策略是要尽可能的将静态文件存储为较长的时间,多利用强缓存而不是协商缓存,即消灭304。

但是给文件设置一个很长的Cacha-Control也会带来其他的问题,最主要的问题是静态内容更新时,用户不能及时获得更新的内容。这时候就要使用hash的方法对文件进行命名,通过每次更新不同的静态文件名来消除强缓存的影响。

Hash命名:

二、分析各个缓存机制

先对各个缓存机制有一个大体的了解,然后才能去考虑如何优化。目前对
浏览器缓存和DOM Storage比较熟悉,其他的大体了解,但是没有项目中用过。

与协商缓存有关的两个属性

If-None-Match/Etag或者If-Modified-Since/Last-Modified

  • Etag是HTTP1.1推荐使用的验证方式,是指根据实体内容生成一段hash字符串,标识资源的状态,由服务端产生。浏览器会将这串字符串传回服务器,验证资源是否已经修改,如果没有修改,过程如下:

    图片 8image.png

  • ETag值通常由服务器端计算,并在响应客户端请求时将它返回给客户端

  • If-Modified-Since与Last-Modified验证过程与etag类似。这两个方式来验证时会存在下面问题:有些文档资源周期性的被重写,但实际内容没有改变。此时文件元数据中会显示文件最近的修改日期与If-Modified-Since不相同,导致不必要的响应。有些文档资源被修改了,但修改内容并不重要,不需要所有的缓存都更新最佳优化策略因为协商缓存本身也有http请求的消耗,所以最佳优化策略就是要尽可能的将静态文件存储为较长的时间,多利用强制缓存而不是协商缓存,这就是消灭304但是给文件设置一个很长的cache-control也会带来很多其他的问题,最主要的问题是静态内容个更新时,用户不能及时获得更新的内容,这个时候就需要利用hash来对文件进行命名,通过每次更新不同的静态文件名来消除强制缓存的影响。(hash值变了,就相当于要请求一个新的文件,那么肯定就跳过协商缓存和强制缓存,直接请求新的文件)

hash命名:

总结

  • 浏览器端缓存分为200 from cache和304 not modified
  • HTTP协议中Cache-Control 和
    Expires可以用来设置新鲜度的限值,前者是HTTP1.1中新增的响应头,后者是HTTP1.0中的响应头。
  • max-age而Expires指定的是具体的过期日期而不是秒数
  • Cache-Control和Expires同时使用的话,Cache-Control会覆盖Expires客户端不用关心ETag值如何产生,只要服务在资源状态发生变更的情况下将ETag值发送给它就行
  • Apache默认通过FileEtag中FileEtag INode Mtime
    Size的配置自动生成ETag(当然也可以通过用户自定义的方式)。
  • ETag常与If-None-Match或者If-Match一起,由客户端通过HTTP头信息发送给服务端处理。
  • Last-Modified常与If-Modified-Since一起由客户端将Last-Modified值包括在HTTP头信息中发给服务端进行处理。
  • 有些文档资源周期性的被重写,但实际内容没有改变。此时文件元数据中会显示文件最近的修改日期与If-Modified-Since不相同,导致不必要的响应。

图片 9image.png

补充说明:web缓存分为两种:

  1. http缓存(从第二次请求开始的,也就是我们上面所说的强制缓存和协商缓存,都是根据response
    header中的一些属性来决定的。)
  2. 浏览器缓存2.1本地存储小容量Cookie主要用于用户信息的存储,Cookie的内容可以自动在请求的时候被传递给服务器。LocalStorage的数据将一直保存在浏览器内,直到用户清除浏览器缓存数据为止。SessionStorage的其他属性同LocalStorage,只不过它的生命周期同标签页的生命周期,当标签页被关闭时,SessionStorage也会被清除。2.2本地存储大缓存
  • IndexDB
  • WebSql

    图片 10image.png

    2.3 应用缓存和PWA

2.2 浏览器缓存

2.1 浏览器缓存机制

浏览器缓存机制是指通过HTTP协议头里的 Cache-Control / Expires 和
Last-Modified / ETag 等字段控制文件缓存的机制。

和 DOM Storage, AppCache 等缓存机制,本质一样。
一个在HTTP协议层实现(浏览器缓存),一个在应用层实现。

2.2.1 本地存储小容量

Cookie主要用于用户信息的存储,Cookie的内容可以自动在请求的时候被传递给服务器。
LocalStorage的数据将一直保存在浏览器内,直到用户清除浏览器缓存数据为止。
SessionStorage的其他属性同LocalStorage,只不过它的生命周期同标签页的生命周期,当标签页被关闭时,SessionStorage也会被清除。

图片 11

2.1.1 强缓存

采用 Cache-Control 和 Expires 来控制缓存。 Chrome开发者工具NetWork,
查看为 form disk cache

图片 12

  • Cache-Control (HTTP1.1标准中新增的字段)

    1. 控制文件本地缓存的有效时间.
    2. Cache-Control:max-age=600
      表示文件本地缓存有效时间600s,接下来600s内请求这个资源,浏览器不发出HTTP请求,直接从本地缓存拿
    3. 是一个相对的时间

  • Expires (HTTP1.0标准中的字段)
    1. Expires: Thu, 10 Nov 2015 08:45:11 GMT
      表示在这个时间前,缓存有效
    2. 是一个绝对时间,由于服务器的时间和客服端的时间可能不一致造成缓存问题,因此引入了HTTP1.1的Cache-Control
    3. 优先级小于 Cache-Control

2.2.2 本地存储大容量

WebSql和IndexDB主要用在前端有大容量存储需求的页面上,例如,在线编辑浏览器或者网页邮箱。

图片 13

2.1.2 协商缓存

HTTP 的状态为 304 表示 协商缓存

图片 14

  • Last-Modified 和 If-Modified-Since

    Last-Modified是标识文件在服务器上的最新更新时间。下次请求时,如果文件缓存过期,浏览器通过If-Modified-Since字段带上这个时间,发送给服务器,由服务器比较时间戳来判断文件是否有修改。如果没有修改,服务器返回304告诉浏览器继续使用缓存;如果有修改,则返回200,同时返回最新的文件。

  • ETag 和 If-None-Match

    Etag也是和Last-Modified一样,对文件进行标识的字段。不同的是,Etag的取值是一个对文件进行标识的特征字串。在向服务器查询文件是否有更新时,浏览器通过If-None-Match字段把特征字串发送给服务器,由服务器和文件最新特征字串进行匹配,来判断文件是否有更新。没有更新回包304,有更新回包200。

Etag和Last-Modified可根据需求使用一个或两个同时使用。两个同时使用时,只要满足基中一个条件,就认为文件没有更新。

2.2.3 应用缓存与PWA

应用缓存全称为Offline Web
Application,它的缓存内容被存在浏览器的Application
Cache中。它也是一个被W3C标准废弃的功能,主要是通过manifest文件来标注要被缓存的静态文件清单。但是在缓存静态文件的同时,也会默认缓存html文件。这导致页面的更新只能通过manifest文件中的版本号来决定。而且,即使我们更新了version,用户的第一次访问还是会访问到老的页面,只有下一次再访问才能访问到新的页面。所以,应用缓存只适合那种常年不变化的静态网站。如此的不方便,也是被废弃的重要原因。

PWA全称是渐进式网络应用,主要目标是实现web网站的APP式功能和展示。尽管PWA也有manifest文件,但是与应用缓存却完全不同。不同于manifest简单的将文件通过是否缓存进行分类,PWA用manifest构建了自己的APP骨架。另外,PWA用Service
Worker来控制缓存的使用。这一块的内容较多,在这里就不详细展开了。

图片 15

2.1.3 F5 和 Ctrl+F5 的特殊情况

手动刷新页面(F5),浏览器会直接认为缓存已经过期(可能缓存还没有过期),在请求中加上字段:Cache-Control:max-age=0,发包向服务器查询是否有文件是否有更新。

可能存在304协商缓存

强制刷新页面(Ctrl+F5),浏览器会直接忽略本地的缓存(有缓存也会认为本地没有缓存),在请求中加上字段:Cache-Control:no-cache(或
Pragma:no-cache),发包向服务重新拉取文件。

不存在强缓存和协商缓存

2.2.4 往返缓存

往返缓存又称为BFCache,是浏览器在前进后退按钮上为了提升历史页面的渲染速度的一种策略。BFCache会缓存所有的DOM结构,但是问题在于,一些页面开始时进行的上报或者请求可能会被影响。这个问题现在主要会出现在微信h5的开发中

去除BFCache有多种方法,但不是本文的重点,想了解的同学可以看《浏览器往返缓存(Back/Forward
cache)问题的分析与解决》

三、LocalStorage, SessionStorage

一个简单的键值对存储系统,接口简单实用,兼容性也很好。有大小限制,提供5M(不同浏览器可能不同,区分host,
cookie 只有 4k)

总结

本文梳理了前端所有可能涉及的缓存,希望能从整体层面建立起系统的缓存知识体系。限于篇幅,每一部分的描述都比较简略,仅起到抛砖引玉之用。如有错误,还望指出。

1 赞 收藏
评论

图片 16

3.1 LocalStorage和 SessionStorage的用法

interface Storage { 

    readonly attribute unsigned long length;

    [IndexGetter] DOMString key(in unsigned long index); 

    [NameGetter] DOMString getItem(in DOMString key); 

    [NameSetter] void setItem(in DOMString key, in DOMString data); 

    [NameDeleter] void removeItem(in DOMString key); 

    void clear();
};

3.2 LocalStorage 和 SessionStorage 的区别

LocalStorage 和 SessionStorage 的区别, SessionStorage
在页面选项卡关闭后,就不存在了, 但是
LocalStorage会还存在。但是注意:页面刷新的时候,SessionStorage还是存在的。

比如在 页面刷新后,表单填写的内容还存在,这个时候使用
SessionStorage最有用了。

3.3 总结

分析:Dom
Storage给Web提供了一种更录活的数据存储方式,存储空间更大(相对Cookies),用法也比较简单,方便存储服务器或本地的一些临时数据。

  • 适合存储简单数据
  • 如果存结构化数据,可以借住JSON的功能
  • 不适合存储复杂,存储空间要求比较大的数据,还有不适合存静态文件

四、Web SQL Database存储机制

目前用来存储结构化数据还是比较主流的一个选择。 参考
《腾讯开发工程师:前端异常监控到底怎么做》&version=12020010&nettype=WIFI&fontScale=100&pass_ticket=DtgeksVBZmbExWTQ%2BdldANzyt56fq2HBKFKNw1N7W9hH8bytHWuxiXpvvgtPj8Au)

IOS下,最大支持50M ,
系统自带浏览器Safari,默认超过5M的时候,会弹出提示让用户增加大小,不太友好。

微信浏览器下,不会提示。

4.1 简单例子

<script>
    if(window.openDatabase){
      //打开数据库,如果没有则创建
      var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024);
       //通过事务,创建一个表,并添加两条记录
      db.transaction(function (tx) {
           tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)');
           tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "foobar")');
           tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "logmsg")');
       });
      //查询表中所有记录,并展示出来
     db.transaction(function (tx) {
         tx.executeSql('SELECT * FROM LOGS', [], function (tx, results) {
             var len = results.rows.length, i;
             msg = "<p>Found rows: " + len + "</p>";
             for(i=0; i<len; i++){
                 msg += "<p>" + results.rows.item(i).log + "</p>";
             }
             document.querySelector('#status').innerHTML =  msg;
             }, null);
      });
}
</script>
<div id="status" name="status">Status Message</div><br>

4.2 分析

  • 适合存储结构复杂的数据
  • 使用起来相对麻烦点,需要了解SQL语句
  • 不是和做静态文件的存储

五、Application Cache 机制

似乎是为了支持 Web App 离线使用二开发的缓存机制。 缓存 和
浏览器缓存机制类似。

  • 按文件单位进行缓存
  • 通过manifest来控制文件的缓存
  • 大小5M的限制

AppCache的原理有两个关键点:manifest属性和 manifest文件。

  • 缓存文件有更新需要更新 manifest文件
    [正常有更新文件就修改mainfest里面的一个版本号]

CACHE MANIFEST
# 2012-02-21 v1.0.0
/theme.css
/logo.gif
/main.js
NETWORK:
login.asp
FALLBACK:
/html/ /offline.html <br>

5.2 分析

分析:AppCache看起来是一种比较好的缓存方法,除了缓存静态资源文件外,也适合构建Web离线
App。在实际使用中有些需要注意的地方,有一些可以说是”坑“。

  1. 要更新缓存的文件,需要更新包含它的manifest文件,那怕只加一个空格。常用的方法,是修改manifest文件注释中的版本号。如:#
    2012-02-21 v1.0.0;

  2. 被缓存的文件,浏览器是先使用,再通过检查manifest文件是否有更新来更新缓存文件。这样缓存文件可能用的不是最新的版本。

  3. 在更新缓存过程中,如果有一个文件更新失败,则整个更新会失败。

  4. manifest和引用它的HTML要在相同Host。

  5. manifest文件中的文件列表,如果是相对路径,则是相对manifest文件的相对路径。

  6. manifest也有可能更新出错,导致缓存文件更新失败。

  7. 没有缓存的资源在已经缓存的HTML中不能加载,即使有网络。例如:http://appcache-demo.s3-website-us-east-1.amazonaws.com/without-network/。

  8. manifest文件本身不能被缓存,且manifest文件的更新使用的是浏览器缓存机制。所以manifest

  9. 文件的Cache-Control缓存时间不能设置太长。
    另外,根据官方文档,AppCache已经不推荐使用了,标准也不会再支持。现在主流的浏览器都是还支持AppCache的,以后就不太确定了。

六、 Indexed Database

IndexedDB也是一种数据库的存储机制,但不同于已经不再支持的Web SQL
Database。IndexedDB不是传统的关系数据库,可归为NoSQL数据库。IndexedDB又类似于Dom
Storage的key-value的存储方式,但功能更强大,且存储空间更大。

  • NoSQL数据库
  • 类似DOM Storage 键值对存储方式

6.1 基本使用

<script type="text/javascript">
var db;
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
//浏览器是否支持IndexedDB
if (window.indexedDB) {
   //打开数据库,如果没有,则创建
   var openRequest = window.indexedDB.open("people_db", 1);
   //DB版本设置或升级时回调
   openRequest.onupgradeneeded = function(e) {
       console.log("Upgrading...");
       var thisDB = e.target.result;
       if(!thisDB.objectStoreNames.contains("people")) {
           console.log("Create Object Store: people.");
           //创建存储对象,类似于关系数据库的表
           thisDB.createObjectStore("people", { autoIncrement:true });
          //创建存储对象, 还创建索引
          //var objectStore = thisDB.createObjectStore("people",{ autoIncrement:true });
         // //first arg is name of index, second is the path (col);
        //objectStore.createIndex("name","name", {unique:false});
       //objectStore.createIndex("email","email", {unique:true});
     }
}
//DB成功打开回调
openRequest.onsuccess = function(e) {
    console.log("Success!");
    //保存全局的数据库对象,后面会用到
    db = e.target.result;
   //绑定按钮点击事件
    document.querySelector("#addButton").addEventListener("click", addPerson, false);
    document.querySelector("#getButton").addEventListener("click", getPerson, false);
    document.querySelector("#getAllButton").addEventListener("click", getPeople, false);
    document.querySelector("#getByName").addEventListener("click", getPeopleByNameIndex1, false);
}
  //DB打开失败回调
  openRequest.onerror = function(e) {
      console.log("Error");
      console.dir(e);
   }
}else{
    alert('Sorry! Your browser doesn\'t support the IndexedDB.');
}
//添加一条记录
function addPerson(e) {
    var name = document.querySelector("#name").value;
    var email = document.querySelector("#email").value;
    console.log("About to add "+name+"/"+email);
    var transaction = db.transaction(["people"],"readwrite");
var store = transaction.objectStore("people");
   //Define a person
   var person = {
       name:name,
       email:email,
       created:new Date()
   }
   //Perform the add
   var request = store.add(person);
   //var request = store.put(person, 2);
   request.onerror = function(e) {
       console.log("Error",e.target.error.name);
       //some type of error handler
   }
   request.onsuccess = function(e) {
      console.log("Woot! Did it.");
   }
}
//通过KEY查询记录
function getPerson(e) {
    var key = document.querySelector("#key").value;
    if(key === "" || isNaN(key)) return;
    var transaction = db.transaction(["people"],"readonly");
    var store = transaction.objectStore("people");
    var request = store.get(Number(key));
    request.onsuccess = function(e) {
        var result = e.target.result;
        console.dir(result);
        if(result) {
           var s = "<p><h2>Key "+key+"</h2></p>";
           for(var field in result) {
               s+= field+"="+result[field]+"<br/>";
           }
           document.querySelector("#status").innerHTML = s;
         } else {
            document.querySelector("#status").innerHTML = "<h2>No match!</h2>";
         }
     }
}
//获取所有记录
function getPeople(e) {
    var s = "";
     db.transaction(["people"], "readonly").objectStore("people").openCursor().onsuccess = function(e) {
        var cursor = e.target.result;
        if(cursor) {
            s += "<p><h2>Key "+cursor.key+"</h2></p>";
            for(var field in cursor.value) {
                s+= field+"="+cursor.value[field]+"<br/>";
            }
            s+="</p>";
            cursor.continue();
         }
         document.querySelector("#status2").innerHTML = s;
     }
}
//通过索引查询记录
function getPeopleByNameIndex(e)
{
    var name = document.querySelector("#name1").value;
    var transaction = db.transaction(["people"],"readonly");
    var store = transaction.objectStore("people");
    var index = store.index("name");
    //name is some value
    var request = index.get(name);
    request.onsuccess = function(e) {
       var result = e.target.result;
       if(result) {
           var s = "<p><h2>Name "+name+"</h2><p>";
           for(var field in result) {
               s+= field+"="+result[field]+"<br/>";
           }
           s+="</p>";
    } else {
        document.querySelector("#status3").innerHTML = "<h2>No match!</h2>";
     }
   }
}
//通过索引查询记录
function getPeopleByNameIndex1(e)
{
    var s = "";
    var name = document.querySelector("#name1").value;
    var transaction = db.transaction(["people"],"readonly");
    var store = transaction.objectStore("people");
    var index = store.index("name");
    //name is some value
    index.openCursor().onsuccess = function(e) {
        var cursor = e.target.result;
        if(cursor) {
            s += "<p><h2>Key "+cursor.key+"</h2></p>";
            for(var field in cursor.value) {
                s+= field+"="+cursor.value[field]+"<br/>";
            }
            s+="</p>";
            cursor.continue();
         }
         document.querySelector("#status3").innerHTML = s;
     }
}
</script>
<p>添加数据<br/>
<input type="text" id="name" placeholder="Name"><br/>
<input type="email" id="email" placeholder="Email"><br/>
<button id="addButton">Add Data</button>
</p>
<p>根据Key查询数据<br/>
<input type="text" id="key" placeholder="Key"><br/>
<button id="getButton">Get Data</button>
</p>
<div id="status" name="status"></div>
<p>获取所有数据<br/>
<button id="getAllButton">Get EveryOne</button>
</p>
<div id="status2" name="status2"></div>
<p>根据索引:Name查询数据<br/>
    <input type="text" id="name1" placeholder="Name"><br/>
    <button id="getByName">Get ByName</button>
</p>
<div id="status3" name="status3"></div><br>

6.2 分析

分析:IndexedDB是一种灵活且功能强大的数据存储机制,它集合了Dom
Storage和Web SQL
Database的优点,用于存储大块或复杂结构的数据,提供更大的存储空间,使用起来也比较简单。可以作为Web
SQL Database的替代。不太适合静态文件的缓存。

  1. 以key-value 的方式存取对象,可以是任何类型值或对象,包括二进制。

  2. 可以对对象任何属性生成索引,方便查询。

  3. 较大的存储空间,默认推荐250MB(分Host),比Dom
    Storage的5MB要大得多。

  4. 通过数据库的事务(tranction)机制进行数据操作,保证数据一致性。

  5. 异步的 API 调用,避免造成等待而影响体验。

七、File System API

  • HTML5新加入的存储机制
  • 为 webApp提供了虚拟的文件系统,类似Native App访问本地系统一样

7.1 File System 的优势

  • 满足大块的二进制文件存储
  • 通过预加载资源文件提供性能
  • 可以直接编辑文件

7.2 两种文件空间

  • 临时型

由浏览器自动分配的,但可能被浏览器收回

  • 持久性

需要显示的申请,申请时浏览器会给用户提示,让用户确定。浏览器不会收回(提供用户则不太友好),大小不够用需要再次申请。

7.3 分析

File System API给Web App带来了文件系统的功能,Native文件系统的功能在Web
App中都有相应的实现。任何需要通过文件来管理数据,或通过文件系统进行数据管理的场景都比较适合。

八、参考文章

  1. 《HTML5缓存机制浅析:移动端Web加载性能优化》
  2. 《腾讯开发工程师:前端异常监控到底怎么做》&version=12020010&nettype=WIFI&fontScale=100&pass_ticket=DtgeksVBZmbExWTQ%2BdldANzyt56fq2HBKFKNw1N7W9hH8bytHWuxiXpvvgtPj8Au)

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 澳门新葡亰官网app 版权所有