indexedDB

一、其它几种前端存储:

1、cookie

HTTP cookie 通常也叫作 cookie,最初用于在客户端存储会话信息。这个规范要求服务器在响应
HTTP 请求时,通过发送 Set-Cookie HTTP 头部包含会话信息。例如, 下面是包含这个头部的一个 HTTP
响应 :

HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value
Other-header: other-header-value

这个 HTTP 响应会设置一个名为"name",值为"value"的 cookie。名和值在发送时都会经过 URL
编码。浏览器会存储这些会话信息,并在之后的每个请求中都会通过 HTTP 头部 cookie 再将它们发回服
务器,比如:

GET /index.jsl HTTP/1.1
Cookie: name=value
Other-header: other-header-value

这些发送回服务器的额外信息可用于唯一标识发送请求的客户端。

cookie 是与特定域绑定的。设置 cookie 后,它会与请求一起发送到创建它的域。这个限制能保证
cookie 中存储的信息只对被认可的接收者开放,不被其他域访问。因为 cookie 存储在客户端机器上,所以为保证它不会被恶意利用,浏览器会施加限制。 同时, cookie也不会占用太多磁盘空间。

cookie 在浏览器中是由以下参数构成的(这些参数在 Set-Cookie 头部中使用分号加空格隔开 ) :

  • 名称:唯一标识 cookie 的名称。 cookie 名不区分大小写,因此 myCookie 和 MyCookie 是同一
    个名称。不过,实践中最好将 cookie 名当成区分大小写来对待,因为一些服务器软件可能这样
    对待它们。 cookie 名必须经过 URL 编码。
  • :存储在 cookie 里的字符串值。这个值必须经过 URL 编码。
  • : cookie 有效的域。发送到这个域的所有请求都会包含对应的 cookie。这个值可能包含子域(如
    www.wrox.com),也可以不包含(如.wrox.com 表示对 wrox.com 的所有子域都有效)。如果不明
    确设置,则默认为设置 cookie 的域。
  • 路径:请求 URL 中包含这个路径才会把 cookie 发送到服务器。例如,可以指定 cookie 只能由
    http://www.wrox.com/books/访问,因此访问 http://www.wrox.com/下的页面就不会发送 cookie,即
    使请求的是同一个域。
  • 过期时间:表示何时删除 cookie 的时间戳(即什么时间之后就不发送到服务器了)。默认情况下,
    浏览器会话结束后会删除所有 cookie。不过,也可以设置删除 cookie 的时间。这个值是 GMT 格
    式( Wdy, DD-Mon-YYYY HH:MM:SS GMT),用于指定删除 cookie 的具体时间。这样即使关闭
    浏览器 cookie 也会保留在用户机器上。把过期时间设置为过去的时间会立即删除 cookie。
  • 安全标志:设置之后,只在使用 SSL 安全连接的情况下才会把 cookie 发送到服务器。例如,请
    https://www.wrox.com 会发送 cookie,而请求 http://www.wrox.com 则不会 ;
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value; expires=Mon, 22-Jan-07 07:10:24 GMT; domain=.wrox.com
Other-header: other-header-value

这个头部设置一个名为"name"的 cookie,这个 cookie 在 2007 年 1 月 22 日 7:10:24 过期,对
www.wrox.com 及其他 wrox.com 的子域(如 p2p.wrox.com)有效。
安全标志 secure 是 cookie 中唯一的非名/值对,只需一个 secure 就可以了。比如:
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value; domain=.wrox.com; path=/; secure
Other-header: other-header-value
这里创建的 cookie 对所有 wrox.com 的子域及该域中的所有页面有效(通过 path=/指定)。不过,
这个 cookie 只能在 SSL 连接上发送,因为设置了 secure 标志。
要知道,域、路径、过期时间和 secure 标志用于告诉浏览器什么情况下应该在请求中包含 cookie。
这些参数并不会随请求发送给服务器,实际发送的只有 cookie 的名/值对 ;

在 JavaScript 中处理 cookie 比较麻烦,因为接口过于简单,只有 BOM 的 document.cookie 属性。
根据用法不同,该属性的表现迥异。要使用该属性获取值时, document.cookie 返回包含页面中所有
有效 cookie 的字符串(根据域、路径、过期时间和安全设置),以分号分隔,如下面的例子所示:
name1=value1;name2=value2;name3=value3
所有名和值都是 URL 编码的,因此必须使用 decodeURIComponent()解码。
在设置值时,可以通过 document.cookie 属性设置新的 cookie 字符串。这个字符串在被解析后会
添加到原有 cookie 中。设置 document.cookie 不会覆盖之前存在的任何 cookie,除非设置了已有的
cookie。设置 cookie 的格式如下,与 Set-Cookie 头部的格式一样:
name=value; expires=expiration_time; path=domain_path; domain=domain_name; secure
在所有这些参数中,只有 cookie 的名称和值是必需的。下面是个简单的例子:
document.cookie = "name=Nicholas";
这行代码会创建一个名为"name"的会话 cookie,其值为"Nicholas"。这个 cookie 在每次客户端向
服务器发送请求时都会被带上,在浏览器关闭时就会被删除。虽然这样直接设置也可以,因为不需要在
名称或值中编码任何字符,但最好还是使用 encodeURIComponent()对名称和值进行编码,比如:
document.cookie = encodeURIComponent("name") + "=" +
encodeURIComponent("Nicholas");
要为创建的 cookie 指定额外的信息,只要像 Set-Cookie 头部一样直接在后面追加相同格式的字
符串即可:
document.cookie = encodeURIComponent("name") + "=" +
encodeURIComponent("Nicholas") + "; domain=.wrox.com; path=/";

因为在 JavaScript 中读写 cookie 不是很直观,所以可以通过辅助函数来简化相应的操作。与 cookie
相关的基本操作有读、写和删除。这些在 CookieUtil 对象中表示如下:

class CookieUtil {static get(name) {let cookieName = `${encodeURIComponent(name)}=`,cookieStart = document.cookie.indexOf(cookieName),cookieValue = null;if (cookieStart > -1){let cookieEnd = document.cookie.indexOf(";", cookieStart);if (cookieEnd == -1){cookieEnd = document.cookie.length;}cookieValue = decodeURIComponent(document.cookie.substring(cookieStart+ cookieName.length, cookieEnd));}return cookieValue;}static set(name, value, expires, path, domain, secure) {let cookieText =`${encodeURIComponent(name)}=${encodeURIComponent(value)}`if (expires instanceof Date) {cookieText += `; expires=${expires.toGMTString()}`;}if (path) {cookieText += `; path=${path}`;}if (domain) {cookieText += `; domain=${domain}`;}if (secure) {cookieText += "; secure";}document.cookie = cookieText;}static unset(name, path, domain, secure) {CookieUtil.set(name, "", new Date(0), path, domain, secure);}
};
// 可以像下面这样使用这些方法:
// 设置 cookie
CookieUtil.set("name", "Nicholas");
CookieUtil.set("book", "Professional JavaScript");
// 读取 cookie
alert(CookieUtil.get("name")); // "Nicholas"
alert(CookieUtil.get("book")); // "Professional JavaScript"
// 删除 cookie
CookieUtil.unset("name");
CookieUtil.unset("book");
// 设置有路径、域和过期时间的 cookie
CookieUtil.set("name", "Nicholas", "/books/projs/", "www.wrox.com",
new Date("January 1, 2010"));
// 删除刚刚设置的 cookie
CookieUtil.unset("name", "/books/projs/", "www.wrox.com");
// 设置安全 cookie
CookieUtil.set("name", "Nicholas", null, null, null, true);
// 这些方法通过处理解析和 cookie 字符串构建,简化了使用 cookie 存储数据的操作

2、Storage

Web Storage 的定义了两个对象: localStorage 和 sessionStorage。 localStorage 是永久存储机制, sessionStorage 是跨会话的存储机制。这两种浏览器存储 API 提供了在浏览器中不受页面刷新影响而存储数据的两种方式。

Storage 类型用于保存名/值对数据,直至存储空间上限(由浏览器决定)。 Storage 的实例与其他
对象一样,但增加了以下方法 :

  • clear():删除所有值;不在 Firefox 中实现。
  • getItem(name):取得给定 name 的值
  • key(index):取得给定数值位置的名称
  • removeItem(name):删除给定 name 的名/值对
  • setItem(name, value):设置给定 name 的值。

sessionStorage:

因为 sessionStorage 对象是 Storage 的实例,所以可以通过使用 setItem()方法或直接给属
性赋值给它添加数据。下面是使用这两种方式的例子:
// 使用方法存储数据
sessionStorage.setItem("name", "Nicholas");
// 使用属性存储数据
sessionStorage.book = "Professional JavaScript";

可以使用 getItem()或直接访问属性名来取得。下面是使用这两种方式的例子:

// 使用方法取得数据
let name = sessionStorage.getItem("name");
// 使用属性取得数据
let book = sessionStorage.book;

可以结合 sessionStorage 的 length 属性和 key()方法遍历所有的值:

for (let i = 0, len = sessionStorage.length; i < len; i++){let key = sessionStorage.key(i);let value = sessionStorage.getItem(key);alert(`${key}=`${value}`);
}
for (let key in sessionStorage){let value = sessionStorage.getItem(key);alert(`${key}=${value}`);
}

要从 sessionStorage 中删除数据,可以使用 delete 操作符直接删除对象属性,也可以使用
removeItem()方法。下面是使用这两种方式的例子:

// 使用 delete 删除值
delete sessionStorage.name;
// 使用方法删除值
sessionStorage.removeItem("book");

sessionStorage 对象应该主要用于存储只在会话期间有效的小块数据。如果需要跨会话持久存储
数据,可以使用 globalStorage 或 localStorage

存储在 localStorage 中的数据会保留到通过 JavaScript 删除或者用户清除浏览器缓存。 localStorage 数据不受页面刷新影响,也不会因关闭窗口、标签页或重新启动浏览器而丢失。

存储事件

每当 Storage 对象发生变化时,都会在文档上触发 storage 事件。使用属性或 setItem()设置
值、使用 delete 或 removeItem()删除值,以及每次调用 clear()时都会触发这个事件。这个事件的
事件对象有如下 4 个属性。

  • domain:存储变化对应的域。

  • key:被设置或删除的键。

  • newValue:键被设置的新值,若键被删除则为 null。

  • oldValue:键变化之前的值。

    可以使用如下代码监听 storage 事件:

    window.addEventListener("storage",(event) => alert('Storage changed for ${event.domain}'
    ));
    

    对于 sessionStorage 和 localStorage 上的任何更改都会触发 storage 事件,但 storage 事
    件不会区分这两者。

二、indexedDB简介

IndexedDB和传统的关系型数据不同的是,它是一个key-value型的数据库。

value可以是复杂的结构体对象,key可以是对象的某些属性值也可以是其他的对象(包括二进制对象)。你可以使用对象中的任何属性做为index,以加快查找。

IndexedDB是自带transaction的,所有的数据库操作都会绑定到特定的事务上,并且这些事务是自动提交了,IndexedDB并不支持手动提交事务。

IndexedDB API大部分都是异步的,在使用异步方法的时候,API不会立马返回要查询的数据,而是返回一个callback。

异步API的本质是向数据库发送一个操作请求,当操作完成的时候,会收到一个DOM event,通过该event,我们会知道操作是否成功,并且获得操作的结果。

IndexedDB是一种 NoSQL 数据库,和关系型数据库不同的是,IndexedDB是面向对象的,它存储的是Javascript对象。

IndexedDB还有一个很重要的特点是其同源策略,每个源都会关联到不同的数据库集合,不同源是不允许访问其他源的数据库,从而保证了IndexedDB的安全性。

三、使用原因:开发者需要在本地进行永久存储

当我们进行一些较大的SPA页面开发时,我们会需要进行一些数据的本地存储。

当数据量不大时,我们可以通过SessionStorage或者LocalStorage来进行存储,但是当数据量较大,或符合一定的规范时,我们可以使用数据库来进行数据的存储。

在浏览器提供的数据库中,共有web sql和IndexedDB两种。相较于HTML5已经废弃的web sql来说,更推荐大家使用IndexedDB。

四、indexedDB的相关操作

// 假如一开始有这样的数据需要存储
let data = [{id: 1,name: "lzc",age: 18,sex: "man",addTime: "2021-2-1"},{id: 2,name: "cb",age: 19,sex: "man",addTime: "2021-2-2"},{id: 3,name: "kj",age: 20,sex: "woman",addTime: "2021-2-3"},{id: 4,name: "juanjuan",age: 21,sex: "woman",addTime: "2021-2-4"}
]

1、创建或者打开数据库

/*
不同的浏览器对于IndexedDB有不同的实现,正常来说,我们可以使用window.indexedDB来获取到浏览器的indexedDB对象。但是对于某些浏览器来说,还没有使用标准的window.indexedDB,而是用带前缀的实现使用IndexedDB第一步,就是创建或打开一个数据库。我们使用window.indexedDB.open(DBName)这个API来打进行操作。
*/
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;if (!window.indexedDB) {console.log("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.");
} else {const request = window.indexedDB.open('people');request.onupgradeneeded = function (event) {}request.onsuccess = function(event) {console.log(request === event.target) // true}request.onerror = function(event) {}
}
  • 调用此接口时,如果当前数据库不存在,则会创建一个新的数据库;
  • 当数据库建立连接时,会返回一个IDBOpenDBRequest对象。
  • 在连接建立成功时,会触发onsuccess事件,其中函数参数eventtarget属性就是request对象。
  • 而在数据库创建或者版本更新时,会触发onupgradeneeded事件。

2、更新数据库版本号

window.indexedDB.open的第二个参数即为版本号。在不指定的情况下,默认版本号为1。

const request = window.indexedDB.open('people', 2);

在需要更新数据库的schema(模式)时,需要更新版本号。此时我们指定一个高于之前版本的版本号,就会触发onupgradeneeded事件。类似的,当此数据库不存在时,也会触发此事件并且将版本更新到置顶版本。

我们需要注意的是,版本号是一个Unsigned long long数字,这意味着它可以是一个非常大的整数。但是,它不能是一个小数,否则它将会被转为最近的整数,同时有可能导致onUpgradeneeded事件不触发(bug)。

3、存储空间操作

我们使用createObjectStore来创建一个存储空间。同时,使用createIndex来创建它的索引。

var request = window.indexedDB.open('people', 1);request.onupgradeneeded = function (event) {console.log(request === event.target) // truevar db = event.target.result;var objectStore = db.createObjectStore('user', {keyPath: 'id', autoIncrement: true});// 可以循环遍历,给对象数组或者对象的每个键都生成索引(每个索引里面的数据项的排序按索引的升序来排列,索引没有顺序可言,就按原始顺序)if (Object.prototype.toString.call(data) === "[object Array]" && data.length) {for (let i in data[0]) {objectStore.createIndex(i, i, { unique: false })}} else if (Object.prototype.toString.call(data) === "[object object]") {for (let i in data) {objectStore.createIndex(i, i, { unique: false })}}
}request.onerror = function (event) {alert("Why didn't you allow my web app to use IndexedDB?!");
};

注:只能在onupgradeneeded回调函数中创建存储空间,而不能在数据库打开后的success回调函数中创建。

通过createObjectStore能够创建一个存储空间。接受两个参数:

  1. 第一个参数,存储空间的名称,即我们上面的user
  2. 第二个参数,指定存储的keyPath值为存储对象的某个属性,这个属性能够在获取存储空间数据的时候当做key值使用。autoIncrement指定了key值是否自增(当key值为默认的从1开始到2^53的整时)。

createIndex能够给当前的存储空间设置一个索引。它接受三个参数:

  1. 第一个参数,索引的名称。
  2. 第二个参数,指定根据存储数据的哪一个属性来构建索引。
  3. 第三个属性, options对象,其中属性unique的值为true表示不允许索引值相等。

4、数据操作

1、事务transaction

IndexedDB中,我们使用事务transaction来进行数据库的操作。事务有三个模式(常量已经弃用)

  • readOnly:只读。
  • readwrite:读写。
  • versionchange:数据库版本变化。

我们创建一个事务时,需要从上面选择一种模式,如果不指定的话,则默认为只读模式

const transaction = db.transaction(['user'], 'readwrite');

事务函数transaction的第一个参数为需要关联的存储空间,第二个可选参数为事务模式。与上面类似,事务成功时也会触发onsuccess函数,失败时触发onerror函数。

2、增加数据

当存储空间objectStore初始化完成后,我们可以把数据放入存储空间中。可以使用 add()或 put()写入数据。这两个方法都接收一个参数, 即要存储的对象,并把对象保存到对象存储。这两个方法只在对象存储中已存在同名的键时有区别。这 种情况下,add()会导致错误,而 put()会简单地重写该对象

var request = window.indexedDB.open('people', 1);request.onsuccess = function (event) {var db = event.target.result;var transaction = db.transaction(['user'], 'readwrite');var objectStore = transaction.objectStore('user');for (let item of data) {objectStore.add(item);}
}

注:add方法中的第二个参数key值是指定存储空间中的keyPath值,如果data中包含keyPath值或者此值为自增值,那么可以略去此参数。

// 1、createObjectStore第二个参数里加 { autoIncrement: true },这个时候key使用从1开始的自增数,遍历出来的数据和原始要存储的数据顺序一致;
// 2、objectStore.add(item, item.name); 指定了keyPath值,这时候遍历出来的数据顺序,可能和原始的不一样,这里是按照keyPath值字母语序来排列的;这里写不写{ autoIncrement: true }都可以;
// 3、createObjectStore第二个参数里加 { keyPath: "name" },这里不能再在objectStore.add(item)里面添加第二个参数,即使这里第二个参数添加的和createObjectStore里面的第二个参数的keyPath的一致;

上面的只影响user对象存储里面的排序,其它索引的排序只和自己的索引有关;

3、查找数据
1、通过特定值获取数据(只能获取单条数据)
  • 这里默认只能获取通过createObjectStore的第二参数的keyPath设置的参数的user对象存储的数据,其它索引的无法查出;
  • 或者使用index方法改变默认索引,比如let store = objectStore.index(“age”),再用store.get(18)就可以通过age来查询了(前提是用createIndex创建了age索引的对象存储,才能使用objectStore.index(“age”),才能查询);
var request = window.indexedDB.open('people', 1);request.onsuccess = function (event) {var db = event.target.result;var transaction = db.transaction(['user'], 'readwrite');var objectStore = transaction.objectStore('user');var request = objectStore.get(1);request.onsuccess = function (event) {//打印搜索的结果console.log(e.target.result);};request.onerror = function (event) {// 错误处理!};
}
2、通过游标获取数据(获取多条数据)

当你需要遍历整个存储空间中的数据时,你就需要使用到游标,与传统数据库查询不同,游标不会事先收集所有结果。相反,游标指向 第一个结果,并在接到指令前不会主动查找下一条数据

var request = window.indexedDB.open('people', 1);request.onsuccess = function (event) {var db = event.target.result;var transaction = db.transaction(['user'], 'readwrite');var objectStore = transaction.objectStore('user');var request = objectStore.openCursor();request.onsuccess = function (event) {var cursor = event.target.result;if (cursor) {console.log(cursor.key, cursor.value);cursor.continue();}};request.onerror = function (event) {// 错误处理!};
}

使用游标时有一个需要注意的地方,当游标遍历整个存储空间但是并未找到给定条件的值时,仍然会触发onsuccess函数。

openCursoropenKeyCursor有两个参数:**openKeyCursor**遍历出来的值里面没有value对象值,其它和openCursor一致

  1. 第一个参数(占位时可以使用null),遍历范围,指定游标的访问范围。该范围通过一个IDBKeyRange参数的方法来获取。 遍历范围参数具体示例如下: ===>这种键范围只能比较其键能比较大小的对象存储或者only这种
// 匹配值 key === 1
const singleKeyRange = IDBKeyRange.only(1);
// 匹配值 key >= 1,lowerBound用于设定结果集的下限,闭集
const lowerBoundKeyRange = IDBKeyRange.lowerBound(1);
// 匹配值 key > 1,lowerBound用于设定结果集的下限,包含该值,设置第二个参数为true时,变为开集
const lowerBoundOpenKeyRange = IDBKeyRange.lowerBound(1, true);
// 匹配值 key < 2,upperBound用于设定结果集的上限,包含该值,设置第二个参数为true时,变为开集
const upperBoundOpenKeyRange = IDBKeyRange.upperBound(2, true);
// 匹配值 key >= 1 && key < 2,指定一个左右范围
const boundKeyRange = IDBKeyRange.bound(1, 2, false, true);
index.openCursor(boundKeyRange).onsuccess = function(event) {   const cursor = event.target.result;   if (cursor) {     // Do something with the matches.     cursor.continue();   }
};
  1. 第二个参数,默认值是next,遍历顺序,指定游标遍历时的顺序和处理相同id(keyPath属性指定字段)重复时的处理方法。改范围通过特定的小写字符串(IDBCursor的常量已经弃用)来获取。其中:
  • next,从前往后获取所有数据(重复值也会遍历出来)
  • prev,从后往前获取所有数据(重复值也会遍历出来)
  • nextunique,从前往后获取数据(重复数据只取第一条,索引重复即认为重复,下同)
  • prevunique,从后往前获取数据(重复数据只取第一条)
var request = window.indexedDB.open('test', 1);request.onsuccess = function (event) {var db = event.target.result;var transaction = db.transaction(['user'], 'readwrite');var objectStore = transaction.objectStore('user');var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound(1, false);var request = objectStore.openCursor(lowerBoundOpenKeyRange, "prev");request.onsuccess = function (event) {var cursor = event.target.result;if (cursor) {console.log(cursor.value);cursor.continue();}};request.onerror = function (event) {// 错误处理!};
}
4、使用索引

在前面构建数据库时,我们创建了所有的索引。现在我们也可以通过索引来进行数据检索。他的本质还是通过之前获取数据的API来进行,只是将原来使用的keyPath属性转换成为了索引指定的属性。

var request = window.indexedDB.open('test', 1);request.onsuccess = function (event) {var db = event.target.result;var transaction = db.transaction(['user'], 'readwrite');var objectStore = transaction.objectStore('user');// 使用索引var index = objectStore.index('name');// 第一种,get方法index.get('a').onsuccess = function (event) {console.log(event.target.result);}// 第二种,普通游标方法index.openCursor().onsuccess = function (event) {console.log('openCursor:', event.target.result.value);}// 第三种,键游标方法,该方法与第二种的差别为:普通游标带有value值表示获取的数据,而键游标没有index.openKeyCursor().onsuccess = function (event) {console.log('openKeyCursor:', event.target.result.key);}
}
5、修改数据===>修改时,须带上这条数据的索引键

注:put方法不仅能够修改现有数据,也能够往存储空间中增加新的数据。

使用objectStore.put方法时,参数为已存在的键,即为修改,为不存在的键时,即为增加;

这里不能像查询一样,通过store.index()来修改索引,index上只有get方法

var transaction = db.transaction(['user'], 'readwrite');
var store = transaction.objectStore("user");// 用put增加一条新数据
var request1 = store.put({id: 5,name: "李志聪",age: 22,sex: "man",addTime: "2021-2-5"
});// 用put增加一条新数据,改sex描述===>是修改时,须带上这条数据的索引键
var request2 = store.put({id: 2,name: "lzc",age: 18,sex: "男",addTime: "2021-2-2"
});request1.onsuccess = function (event) {}
6、删除数据
var transaction = db.transaction(['user'], 'readwrite');
var store = transaction.objectStore("user");var request = store.delete(对应某一条keyPath值);request.onsuccess = function (event) {}
7、关闭数据库
// 比如在destoryed钩子里面可以关闭数据库
db.close();

五、安全相关

IndexedDB也受到浏览器同源策略的限制。

六、dexie.js库的使用

dexie.js:A Minimalistic Wrapper for IndexedDB

基于indexDB的Dexie数据库

// 下面配一个简单的演示// 创建一个数据库 若数据库已存在则为打开
// 打开数据库时,会判断当前version值是否大于已经存在的version值,若大于则会upgrade即升到最高版本
var db = new Dexie("mydb");// 设定版本,添加一个person表,里面有自增的id主键,有name和age两个索引
// 注意:不要像在SQL中那样声明所有列。只声明要索引的属性,即要在where(…)查询中使用的属性。
db.version(1).stores({person: "++id, name, age"
})// 增加(还是使用上面的数据进行存储)
for(let item of data) {db.person.add(item)
}// 修改
setTimeout(() => {db.person.put({id: 2,name: "聪波",age: 18,sex: "boy",addTime: "2021-2-2"})console.log(db.person.get(2)) // 一个promise对象// 普通查询db.person.get(2).then(res => {console.log("查询的结果为===>", res)})
}, 1000)// 带条件查询
setTimeout(() => {// adove、aboveOrEqual、below、belowOrEqual、between、equalsdb.person.where("age").aboveOrEqual(18).toArray().then(res => {console.log("年龄大于等于18岁的有===>", res)})
}, 2000)// 删除
setTimeout(() => {// 删除第一条db.person.delete(1);db.person.get(1).then(res => {console.log("第一条数据===>", res)})
}, 3000)setTimeout(() => {db.close();console.log("要是数据库没有关闭,下面将打印第三天数据");db.person.get(3).then(res => {console.log("第三条数据===>", res)})
}, 4000)

indexedDB简单介绍相关推荐

  1. 遗传算法的简单介绍以及模式定理的简单证明

    遗传算法   遗传算法(Genetic Algorithm,GA),最早是由美国的John holland在20世纪70年代提出.算法通过模拟达尔文生物进化论的自然选择以及遗传学机理的生物进化过程来搜 ...

  2. 2021年大数据ELK(十八):Beats 简单介绍和FileBeat工作原理

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 Beats 简单介绍和FileBeat工作原理 一.Beats 二.FileB ...

  3. 2021年大数据ELK(十五):Elasticsearch SQL简单介绍

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 Elasticsearch SQL简单介绍 一.SQL与Elasticsear ...

  4. 2021年大数据ELK(二):Elasticsearch简单介绍

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 系列历史文章 一.Elasticsearch简介 1.介绍 2.创始人 二.E ...

  5. iOS开发UI篇—多控制器和导航控制器简单介绍

    iOS开发UI篇-多控制器和导航控制器简单介绍 一.多控制器 一个iOS的app很少只由一个控制器组成,除非这个app极其简单.当app中有多个控制器的时候,我们就需要对这些控制器进行管理 有多个vi ...

  6. 简单介绍一下R中的几种统计分布及常用模型

    统计学上分布有很多,在R中基本都有描述.因能力有限,我们就挑选几个常用的.比较重要的简单介绍一下每种分布的定义,公式,以及在R中的展示. 统计分布每一种分布有四个函数:d――density(密度函数) ...

  7. LVS(Linux Virtual Server)三种负载均衡模型和十种调度的简单介绍

    LVS(Linux Virtual Server)三种负载均衡模型和十种调度的简单介绍 LVS (Linux Virtual Server) LVS(Linux Virtual Server)其实就是 ...

  8. dubbo学习过程、使用经验分享及实现原理简单介绍

    一.前言 部门去年年中开始各种改造,第一步是模块服务化,这边初选dubbo试用在一些非重要模块上,慢慢引入到一些稍微重要的功能上,半年时间,学习过程及线上使用遇到的些问题在此总结下. 整理这篇文章差不 ...

  9. iOS开发UI篇—UIWindow简单介绍

    iOS开发UI篇-UIWindow简单介绍 一.简单介绍 UIWindow是一种特殊的UIView,通常在一个app中只会有一个UIWindow iOS程序启动完毕后,创建的第一个视图控件就是UIWi ...

最新文章

  1. 杨威(为奥运冠军名字作诗)
  2. ExtJs 备忘录(6)—— GirdPanl表格(二) [ 搜索分页 ]
  3. C#创建Word文档
  4. springMVC简单实例
  5. JAVA面试题解惑系列(四)——final、finally和finalize的区别
  6. 俩虚拟机间通过ssh互相登陆
  7. arm rtx教程_ARM CMSIS标准概述及快速入门
  8. tableview,基本属性图片详细解释
  9. 程序员是终身学习的职业,应该怎么学习?
  10. 算法—回溯法桥本分数式
  11. 李牛(Linux)vi
  12. phpstorm xdebug配置
  13. 不用Linux也可以的强大文本处理方法
  14. PHP扩展库PEAR被攻击,近半年下载者或被影响
  15. 创新数字音频处理技术带来消费电子产品差异化用户体验(转)
  16. cdh用户权限_CDH6.3.2之Sentry权限管理(三)
  17. 项目管理中的小组周报模板
  18. Centos7 完全卸载MySQL8.0
  19. 12月PMP备考~通关宝典
  20. 齐次坐标 (Homogeneous Coordinate)

热门文章

  1. Reasoning with Sarcasm by Reading In-between读书笔记
  2. 端粒效应《The Telemere Effect》程序员的养生指南(二)情绪、思维模式与健康
  3. html程序国庆节祝福,2018有关于国庆节的祝福语
  4. 计算机没有外审的核心期刊,国内核心期刊投稿经验总结战友们共同分享丁香园论坛...
  5. trx40主板支持服务器内存,华硕发布TRX40系列主板:8内存插槽设计+64个PCIe 4.0通道...
  6. VPB测试 使用Osgdem运行例子
  7. 亲身实践已解决:Mysql Row size too large ( 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT
  8. 基于 Nios II 的串口打印和流水灯设计【使用 Quartus 软件】【掌握 SOPC 开发流程】
  9. 常用控件 — 列表视图
  10. ibm服务器做系统按f几,台式机华硕主板u盘启动按f几(启动u盘的快捷键介绍)...