前言:这是一篇译文(原文),虽然在《高程3》第23章有IDB的更详细介绍,但是有点过时了,这篇文章基本概括了IDB的简单知识点,如果需要更详尽的了解可以参照IDB标准。
简介
HTML5提供的API中包括IndexedDB API。相比web storage API以键值对的形式在客户端存储数据,IDB是一种更为成熟的索引数据库。通过使用IDB,可以更好的构建离线web应用,并且通过将数据存储在浏览器而非服务器一侧,降低了服务器和浏览器的交互次数,提高了性能。本文主要介绍IDB API的基本概念。
1)背景:什么是IDB?
IDB API源于浏览器自带的index database,该数据库包含简单值和对象的记录。每个记录都包含键名和以及对应的值,这些值可以是对象或者基本数据类型。IDB API有两种形式:同步或者异步。一般都是使用异步API。IDB API通过window.indexedDB对象实现,这个API在各大浏览器的支持形式并不统一,一般使用浏览器的前缀区别。
因此,为了实现跨浏览器兼容,最好在使用IDB API之前进行一个声明:
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
2)创建数据库
在使用IDB之前需要创建一个数据库。由于数据库是异步工作模式,调用open()方法将会返回一个IDBRequest对象,通过这个对象可以绑定成功或错误的事件处理程序。以下是一个实例:
var db;
var request = indexedDB.open("TestDatabase");
request.onerror = function(evt) {
console.log("Database error code: " + evt.target.errorCode);
};
request.onsuccess = function(evt) {
db = request.result;
};
在上例中,调用open()创建了名为TestDatabase的IDB数据库。随后给返回的IDBRequest对象绑定了onerror和onsuccess事件处理程序。在onsuccess回调函数中,可以通过IDBRequest对象的 result属性得到数据库对象,留待随后使用。
实际上,open()函数包含的第二个参数没有显式列出,第二个参数一般是数据库版本号。该参数用来更改数据库版本,如果数据库版本比参数表示的版本低,将会触发upgradeneeded事件,并在其事件处理程序中改变数据库结构。更改版本号是唯一可以改变数据库结构的方式。
3)创建对象存储空间
一个IDB数据库可以包含对个对象存储空间,一个对象存储空间类似于关系型数据库(如MySQL中)中的表。可以使用IDBRequest对象的createObjectStore()方法创建对象空间,该方法包含两个参数,第一个参数是对象空间的名字,另一个是选项对象,包含keyPath属性和keyGenerator值,keyPath属性是空间中要保存的对象的属性,这个属性将作为存储空间的键来使用。如果对象中没有具有确切名字的属性可以keyPath,可以使用autoIncrement作为keyGeneraotr。autoIncrement可以表示任意对象属性。
对象存储空间可以具有进行数据检索的索引,索引可以通过对象存储空间的createIndex()创建,具有三个参数:索引名、放置索引的属性名、以及选项对象。以下是一个在ungradeneeded事件处理程序中创建对象存储空间的例子:
var peopleData = [
{ name: "John Dow", email: "john@company.com" },
{ name: "Don Dow", email: "don@company.com" }
];
function initDb() {
var request = indexedDB.open("PeopleDB", 1);
request.onsuccess = function (evt) {
db = request.result;
};
request.onerror = function (evt) {
console.log("IndexedDB error: " + evt.target.errorCode);
};
request.onupgradeneeded = function (evt) {
var objectStore = evt.currentTarget.result.createObjectStore("people",
{ keyPath: "id", autoIncrement: true });
objectStore.createIndex("name", "name", { unique: false });
objectStore.createIndex("email", "email", { unique: true });
for (i in peopleData) {
objectStore.add(peopleData[i]);
}
};
}
上例具有以下作用:
1)ongradeneeded在Onsuccess回调之前作用,可以通过evt.currentTarget.result访问到刚刚创建的数据库。
2)keyPath属性“id”在对象中并不存在,因此使用autoincrement产生自增的keyGenerator。
3)在创建索引的时候可以使用unique限制索引值得唯一性。
4)对象存储空间的add()或put()方法可以添加数据。
4) 检索数据—创建事务
当创建了对象存储空间并添加过数据之后,自然就需要访问数据。访问数据要通过IDBTransaction对象,这个对象也不具有浏览器兼容性,因此要进行跨浏览器声明:
var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
这个IDBTransaction对象有三种模式:read-only, read/write and snapshot。一般情况下事务默认为可读模式。取得了事务的索引之后,通过objectStore()方法并传入存储空间的名称,就可以访问特定的存储空间,然后就可以通过get()/add()/put()/delete()/clear()方法进行数据的检索、增加、删除。事务处理是异步响应,因此返回请求对象,对这个请求对象可以绑定onerror、onsuccess和oncomplete事件处理程序。
var transaction = db.transaction("people", IDBTransaction.READ_WRITE);
var objectStore = transaction.objectStore("people");
var request = objectStore.add({ name: name, email: email });
request.onsuccess = function (evt) {
// do something when the add succeeded
};
5) 检索数据—游标
通过事务的get()方法可以检索数据,但是这需要你事先知道数据的keyPath。除此之外还可以通过游标检索数据,在事务指定的对象存储空间上使用openCursor()方法创建游标,该方法也是返回一个请求对象,可以绑定onerror或onsuccess。在onsuccess事件处理程序中通过event.target.result取得存储空间的下一个对象, 在结果集中有下一项时,这个属性中保存一个 IDBCursor 的实例,在没有下一项时,这个属性的值为 null。 IDBCursor 的实例有以下几个属性。
a) direction:数值,表示游标移动的方向。默认值为 IDBCursor.NEXT(0),表示下一项。 IDBCursor.NEXT_NO_DUPLICATE(1)表示下一个不重复的项,DBCursor.PREV(2)表示前一项,而IDBCursor.PREV_NO_DUPLICATE 表示前一个不重复的项。
b) key:对象的键。
c) value:实际的对象。
d) primaryKey:游标使用的键。可能是对象键,也可能是索引键。
默认情况下,每个游标只发起一次请求,因此,还需要移动游标实现存储空间的遍历。这就依靠下面的方法:
a)continue(key):移动到结果集中的下一项。参数 key
是可选的,不指定这个参数,游标移动到下一项;指定这个参数,游标会移动到指定键的位置。b)advance(count):向前移动 count 指定的项数。这两个方法都会导致游标使用相同的请求,因此相同的 onsuccess
和 onerror 事件处理程序也会得到重用。
一个实例:
var transaction = db.transaction("people", IDBTransaction.READ_WRITE);
var objectStore = transaction.objectStore("people");
var request = objectStore.openCursor();
request.onsuccess = function(evt) {
var cursor = evt.target.result;
if (cursor) {
output.textContent += "id: " + cursor.key + " is " + cursor.value.name + " ";
cursor.continue();
}
else {
console.log("No more entries!");
}
};
上例在名为people的对象存储空间上创建事务,然后在该存储空间上通过openCursor()创建游标,在返回的请求对象上调用evt.target.result得到对象实例,然后通过对象实例的key和value属性填充名为output的DIV。最后通过continue()方法进行遍历。
6) IDB和web storage对比
当需要存储少量的键值对数据时,web storage比IDB更合适;但是当需要存储更多数据并且需要快速检索时,使用IDB更合适。两者是互补的关系。IDB的标准可以参照这个。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。