问题:你在学习indexedDB时你一般从哪几个方面下手呢,有没有一个大致的学习或执行思路?
针对上面的问题,我们对indexedDB的入门使用进行整理
学习或执行思路:
1、新建一个数据库(有则打开,无则新建打开)
2、在数据库中创建一个对象存储or对象仓库
3、启动事务并请求执行一些数据库操作,如添加和检索数据(indexedDB关于数据的操作全部在事务中进行)
4、通过侦听正确的DOM事件来判断数据操作的结果是否正确并在对应的回调中对结果做一些事情
针对上面的4个学习思路,我们将indexedDB的入门使用分为如下10个部分。其中前9个部分是indexedDB的具体使用代码。组合到一起就是indexedDB入门使用的全部代码。最后一个部分是很重要的说明和个人理解。
1、如何在不同的浏览器种使用IndexedDB对象呢?
如果要在仍使用前缀的浏览器中测试代码,则可以使用以下代码:
// 在接下来的代码行中,您应该包含要测试实现的前缀。indexedDB属于window的内置对象,所以可以不加window前缀
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
// 如果不是在一个函数or方法中,那么不要使用 "var indexedDB = ..."
// 只有在旧浏览器需要支持对象的常量时才需要这一行
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE: "readwrite"};
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
// 注:Mozilla从来没有给这些对象加上前缀,所以我们不需要window.mozIDB*
请注意,使用前缀的实现可能有错误,或者不完整,或者遵循该规范的旧版本。因此,不建议在生产代码中使用它。不支持浏览器比宣称支持浏览器并失败可能更合适:
// 第一种判断表达方式
if (!window.indexedDB) {
console.log("当前浏览器不支持IndexedDB");
}
// 第二种判断表达方式
if(!('indexedDB' in window)){
console.log('当前浏览器不支持IndexedDB');
}
2、打开(连接)一个数据库
// 返回一个IDBOpenDBRequest对象,该对象具有作为事件处理的成功或错误值
// 对于open()的第一个参数数据库名,open()会先去查找本地是否已有这个数据库,
// 如果有则直接将这个数据库返回,如果没有,则先创建这个数据库,再返回。
// 对于第二个参数版本号,则是一个可选参数,如果不传,默认为1,
// 但是如果传入必须是一个整数
// 注:浏览器常用于在任何给定的Web应用程序首次尝试打开IndexedDB进行存储时提示用户
var resquest = window.indexedDB.open("myTestDatabase", 1); // or var resquest = indexedDB.open("myTestDatabase", 1);
3、在成功事件回调中保存IDBDatabase的结果实例
// 对所生成的所有请求执行的第一件事是添加成功和错误处理程序
var db;
resquest.onsuccess = function(event) {
db = event.target.result;
console.log("连接成功");
}
resquest.onerror = function(event) {
console.log("连接失败");
}
4、数据库中的错误处理(针对db的所有错误操作都会进入到onerror错误处理回调函数)
db.onerror = function(event) {
// 针对此数据库请求的所有错误的通用错误处理程序
console.error("Database error: " + event.target.errorCode);
};
// 注:打开数据库的常见错误之一是VER_ERR,它指磁盘上存储的数据库版本大于您尝试打开的版本
5、创建或更新数据库的版本(对象仓库)
// 当创建新数据库或者增加现有数据库的版本号时(通过指定更高的版本号)
// 回调至onupgradeneeded,并应该在此创建此版本数据库所需的对象库
// 这个事件一般只有最新的浏览器才存在
// onupgradeneeded是唯一可以更改数据库结构的地方,且回调的相应顺序优先于onsuccess回调事件
request.onupgradeneeded = function(event) {
// Save the IDBDatabase interface
var db = event.target.result;
// Create an objectStore for this database
// createObjectStore()方法接受两个参数,第一个是对象仓库的名称,
// 在同一个数据库中,仓库名不能重复,
// 第二个参数是可选参数,用于指定数据的主键,以及是否自增主键
var objectStore = db.createObjectStore("name", { keyPath: "myKey", autoIncrement: false});
};
// 注:在此种情况下,数据库将已经具有数据库先前版本中的对象存储,
// 因此您不必再次创建这些对象存储。您只需要创建任何新的对象库,
// 或从不再需要的先前版本中删除对象库。如果您需要更改现有的对象库
// (例如,更改keyPath),则必须删除旧的对象库并使用新选项再次创建它。
// (请注意,这将删除对象存储中的信息!如果需要保存该信息,
// 则应在升级数据库之前将其读出并保存在其他位置。)
6、构建一个数据库来存储数据
var customerData = [
{ ssn: "444-44-4444", name: "Bill", age: 35, email: "bill@company.com" },
{ ssn: "555-55-5555", name: "Donna", age: 32, email: "donna@home.org" }
];
var DB_NAME = "your db name";
var DB_VERSION = 1;
var DB_STORE_NAME = "your db store name";
// 连接数据库
var resquest = indexedDB.open(DB_NAME, DB_VERSION);
// 错误处理
resquest.onerror = function(event){
console.error("Database error: " + event.target.errorCode);
}
// 成功处理
resquest.onsuccess = function(event){
var db = event.target.result;
var objectStore = db.createObjectStore("your db store name", {keyPath: "根据数据指定的对象数据主键"})
// 创建索引,参数来源于数据对象的属性。unique确保每条记录的唯一性
objectStore.createIndex("same with next param", "your db store attribute name 1", {unique: false});
objectStore.createIndex("same with next param", "your db store attribute name 2", {unique: true});
// 使用transacton()来创建一个事务,transaction()接受两个参数
// 第一是要操作的对象仓库名称,第二个是你创建的事务模式readonly or readwrite
// 在添加数据前需要确保存储仓库创建完成(即表)。可以使用oncomplete方法
objectStore.transaction.oncomplete = function(event) {
var customerTA = db.transaction("your db store name", "readwrite");
// or var customerTA = db.transaction(["your db store name"], "readwrite");
var operateObjectStore = customerTA.objectStore("your db store name");
// 添加数据
customerData.forEach(function(customer) {
operateObjectStore.add(customer);
});
};
}
7、操作数据
add():增加数据。接受一个参数,为需要保存到对象仓库中的对象
put():增加或修改数据。接受一个参数,为需要保存到对象仓库中的对象
get():获取数据。接受一个参数,为需要获取数据的主键值
delete():删除数据。接受一个参数,为需要获取数据的主键值
注:put保存数据时,该数据的主键在数据库中已经有相同主键的时候,则会修改数据库中对应主键的对象,而使用add保存数据,如果该主键已经存在,则保存失败
// 前置代码和第6部分相同,这里只演示如何对数据进行操作
var customerData = {
{ id: 0, ssn: "444-44-4444", name: "Bill", age: 35, email: "bill@company.com" },
{ id: 1, ssn: "555-55-5555", name: "Donna", age: 32, email: "donna@home.org" }
}
// add() 插入数据的示例
customerData.forEach(function(customer) {
var addRequest = operateObjectStore.add(customer);
addRequest.onsuccess = function (event) {
console.log('数据写入成功');
};
addRequest.onerror = function (event) {
console.log('数据写入失败');
};
});
// put() 修改数据示例
// 待修改数据的主键要和数据库本身存在的一致,如修改第二行数据
var putRequest = operateObjectStore.put({ id: 1, ssn:'555-55-6666', name: 'jsdashf', age: 20,email:'ant@163.com' });
putRequest.onsuccess = function (event) {
console.log('数据更新成功');
};
putRequest.onerror = function (event) {
console.log('数据更新失败');
}
// get() 获取数据示例
var getid = 1;
var getRequest = operateObjectStore.get(getid);
getRequest.onsuccess = function(event){
console.log('数据查找成功');
};
getRequest.onerror = function(event){
console.log('数据查找失败');
};
// delete() 删除数据示例
var deleteid = 1;
var deleteRequest = operateObjectStore.delete(deleteid);
deleteRequest.onsuccess = function(event){
console.log('数据删除成功');
};
deleteRequest.onerror = function(event){
console.log('数据删除失败');
};
// 注:批量其实就是循环,暂时没看到有批量操作的api,如果有后期再补充。
8、使用游标
游标用于一次性获取一个区间内的数据。要使用游标,需要使用对象仓库上的openCursor()方法创建并打开。openCursor()方法接受两个参数
openCursor(range?: IDBKeyRange | number | string | Date | IDBArrayKey, direction?: IDBCursorDirection): IDBRequest;
第一个是范围,范围可以是一个IDBKeyRange对象,用以下方式创建
// boundRange 表示主键值从1到10(包含1和10)的集合。
// 如果第三个参数为true,则表示不包含最小键值1,如果第四参数为true,则表示不包含最大键值10,默认都为false
var boundRange = IDBKeyRange.bound(1, 10, false, false);
// onlyRange 表示由一个主键值的集合。only() 参数则为主键值,整数类型。
var onlyRange = IDBKeyRange.only(1);
// lowerRaneg 表示大于等于1的主键值的集合。
// 第二个参数可选,为true则表示不包含最小主键1,false则包含,默认为false
var lowerRange = IDBKeyRange.lowerBound(1, false);
// upperRange 表示小于等于10的主键值的集合。
// 第二个参数可选,为true则表示不包含最大主键10,false则包含,默认为false
var upperRange = IDBKeyRange.upperBound(10, false);
第二个参数是方向
next:游标中的数据按主键值升序排列,主键值相等的数据都被读取
nextunique:游标中的数据按主键值升序排列,主键值相等只读取第一条数据
prev:游标中的数据按主键值降序排列,主键值相等的数据都被读取
prevunique:游标中的数据按主键值降序排列,主键值相等只读取第一条数据
var objectStore = db.transaction("customers").objectStore("customers");
var customers = [];
objectStore.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
console.log("Name for SSN " + cursor.key + " is " + cursor.value.name);
customers.push(cursor.value);
cursor.continue(); // 用于区间循环
}
else {
console.log("No more entries!");
}
};
9、使用索引
// First, make sure you created index in request.onupgradeneeded:
// objectStore.createIndex("name", "name");
// Otherwize you will get DOMException.
var index = objectStore.index("name");
index.get("Donna").onsuccess = function(event) {
console.log("Donna's SSN is " + event.target.result.ssn);
};
// 注:若索引不唯一,那么当有多个重复记录时,总是会得到键值最低的那个。
10、说明和个人理解
indexedDB不是传统意义上的浏览器缓存而是本地存储。注意区分
indexedDB是在回调相应函数中表示上一次的操作结果,属于异步过程,相应的操作都要在上一次的正确操作后再进行。绝大部分操作是异步的,上面9个部分全是异步操作。
网友评论