IndexedDB 中文教程(1)介绍

IndexedDB 中文教程(1)介绍

IndexedDB 中文教程(2)基本使用

教程持续更新中……

参考

[1] 《IndexedDB》 - https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API


概述

IndexedDB 是一种 web 浏览器中持久存储数据的方法,是一种“NoSQL”数据库。IndexedDB 提供了高性能的接口,适用于大量数据的本地读写和持久存储,对于开发可离线 Web
应用意义非凡。

Web 本地存储有很多方法可选,早期可选的方法可能只有 cookie。但 cookie 的初衷并非单纯用来做本地存储的,而是用来记录一些用户身份信息,便于网站标识访问者身份。因此 cookie 的可用大小有限,并且会被 HTTP 请求携带,造成了不必要的网络性能开销,尤其是在较差的网络环境中,这些开销将导致极差的体验。

在新的 HTML 标准中提供了 Web Storage API,包括 sessionStoragelocalStorage 两种机制。新的 API 配合 Ajax 在很多场景中完全可以替代 cookie,并且存储容量限制大大提高。两个接口不同的生命周期机制也提供了一定的方便。

虽然不同于 cookie 的字符串存储的方式,Web Storage API 提供了键值对的存储方式。但对于复杂数据来说,依然只能通过格式化后的字符串去存储数据,这就决定了 Web Storage API 在进行复杂数据的修改和查询时很不方便。更关键的是,Web Storage API 是同步接口,会同步阻断浏览器 JavaScript 进程。当数据量比较大,或操作比较复杂时,这两个缺陷将会带来致命的性能问题。

随着移动互联网发展和技术进步,用户和开发者对 Web 应用的期望越来越高,Web 应用需要承担越来越多的任务。体现在可离线应用和数据持久化方面,对于本地化数据存储的要求也越来越高。浏览器本地数据库被设计和实现出来,关系型数据库 WebSql 出现了,大量的数据存储和对 SQL 语句的支持,大大提高了浏览器本地数据存储能力。

2010 年 W3C 组织废弃了 WebSql,key-value 数据库 IndexedDB 成为其替代品。

例子

为了方便介绍和观察 IndexedDB 的结构和特点,我们先创建一个 IndexedDB 的简单实例。

复制以下代码到 Chrome 中并执行。该代码将创建一个 IndexedDB 数据库,并建立一个 ObjectStore(对象仓库),同时存储了一条数据到数据库中。

可以不必在意代码的实现细节,后续会详细介绍。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
(function () {
if (!window.indexedDB) {
console.log('浏览器不支持 indexedDB');
return;
}

var delReq = window.indexedDB.deleteDatabase('hozen.site');
delReq.onsuccess = initDB;

function initDB() {
var openReq = window.indexedDB.open('hozen.site');
openReq.onupgradeneeded = function () {
openReq.result.createObjectStore('blog');
}
openReq.onsuccess = function () {
var db = openReq.result;
var store = db.transaction('blog', 'readwrite').objectStore('blog');
store.add({
name: 'indexDB',
author: 'hozen',
}, 1);
}
openReq.onerror = function (e) {
console.log('打开数据库失败', e);
}
}
})();

代码执行成功后,打开 Chrome 的开发者工具,在 Application 面板中找到 IndexedDB 选项,打开就能查看一个最简单的 IndexedDB 的样例了。

有了这个例子,我们可以分析一些 IndexedDB 的显著特点。

特性

面向对象数据库

IndexedDB 是不需要 SQL 语句来操控的,是面向对象数据库。

从例子中可以看出,IndexedDB 数据库并不具备类似关系数据库的表结构和固定的字段。在同一个源下,可以存在多个不同名的数据库,每个数据库下包含若干个对象仓库(Object Store),对象仓库是 Key-Value 结构的。你可以将数据(甚至是 JavaScript 对象)存储到对象仓库中,需要时通过键或索引快速的读出数据。

这种面向对象的设计,允许直接对 JavaScript 对象进行存取,使得数据库的灵活性大大提高,读取存储数据的格式转化成本也大大下降。也规避了关系型数据库中需求变更时,需要对表结构进行修改甚至重新设计的风险。

key-value 数据库

与传统的关系型数据库不同,IndexedDB 是 kye-value 数据库。value 可以是非常复杂的对象,key 可以是对象自身的属性。可以对对象的某个属性创建索引来实现快速查询和列举排序。并且,key 的数据类型几乎没有限制,甚至可以是二进制对象。

事务模式数据库

对于 IndexedDB 数据的操作都必须在一个事务中完成,因此 IndexedDB 基本(对于持久性,IndexedDB 在实现中是有一个默认的 BUG 的,参见)保证了原子性、一致性、隔离性和持久性,减少了数据混乱的机会。

异步

IndexedDB API 基本上是异步的。当对 IndexedDB 数据库进行读写等操作时,会向数据库发送一个操作请求,当操作完成时数据库会通过事件通知我们。这类似 Ajax 请求,这样的好处在于程序不会阻塞在数据库操作过程,对于大量复杂数据的操作,这一点是很重要的。

IndexedDB 标准中提供了同步接口,但这些同步接口只能用于 Web Workers

同源策略

IndexedDB 同样遵循同源策略,即对于不同的应用层协议、域名、端口产生不同的“源”。在不同的“源”之间,数据是不会相互干扰和作用的,在同一个“源”内所有的数据库都有唯一的名称。

容易理解,同源策略是为了数据安全考虑。

局限性

IndexedDB 是有一些局限性的,下面的内容只是指导性的,一些特性和原因后面的教程中会进行解释。

以下情况不适合使用IndexedDB

  • 全球多种语言混合存储。国际化支持不好。需要自己处理。
  • 和服务器端数据库同步。你得自己写同步代码。
  • 全文搜索。IndexedDB 接口没有类似 SQL 语句中 LIKE 的功能。

注意,在以下情况下,数据库可能被清除:

  • 用户请求清除数据。
  • 浏览器处于隐私模式。最后退出浏览器的时候,数据会被清除。
  • 硬盘等存储设备的容量到限。
  • 数据损坏。
  • 进行与特性不兼容的操作。