使用indexedDB(一)(翻译)

IndexedDB是一种可以让您在用户浏览器中持久保存数据的方法。因为它可以让您创建带有强大的数据检索能力的web应用,即使在离线情况下依然可用。


关于本文档

本教程让您轻松掌握IndexedDB异步API。如果您还不太熟悉IndexedDB的基础知识,请参考IndexedDB的基本概念。

关于IndexedDB API的参考文档,可以参看IndexedDBarticle and its subpages,列出了IndexedDB中使用的对象类型,同步API和异步API的方法(method)


使用IndexedDB的通常方法步骤:


1打开一个数据库

2在数据库中创建一个对象object store

3开启一个事务transaction并创建一个数据库操作请求request,比如插入数据、或者查询数据

4监听DOM事件,等待操作完成。

5对结果result执行一些处理(结果result在返回的request中)。

遵循这些重点步骤,我们可以得到更多的信息。


创建和结构化对象

因为(indexedDB的)规范还在不断完善中,当前版本的IndexedDB掩盖了在浏览器中被支持的前缀。在(indexedDB的)规范形成最后版本之前,浏览器生产商可能支持不

同版本的标准IndexedDB API。但是,一旦(indexedDB官方与浏览器生产商)达成了一致,生产商将实现无前缀的统一IndexedDB版本。实际上,一些版本已经实现了无前

缀(统一):Internet Explorer10, Firefox 16, Chrome 24。当使用前缀时,基于Gecko的浏览器使用moz前缀,基于WebKit的浏览器使用webkit前缀。


使用实验性(meta)版本的IndexedDB

如果您想在依然需要前缀才能支持IndexedDB的浏览器中测试您的程序,您可以使用如下代码:

// In the following line, you should include the prefixes of implementations you want to test.
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
// DON'T use "var indexedDB = ..." if you're not in a function.
// Moreover, you may need references to some window.IDB* objects:
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE: "readwrite"}; // This line should only be needed if it is needed to support the object's constants for older browsers
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
// (Mozilla has never prefixed these objects, so we don't need window.mozIDB*)


请注意,带有前缀的版本可能是不正常、不完整的,或者参照了旧版本的规范。因此,不建议在正式产品中使用。

也许【明确表明不支持】要比【承诺了支持,但是却失败了】要更好一些。

if (!window.indexedDB) {
    window.alert("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.");
}


打开数据库

我们这样开始:

// Let us open our database
var request = window.indexedDB.open("MyTestDatabase", 3);


注意,打开数据库正如其它任何的操作——您必须申请它。

【打开】申请不会打开马上数据库或者开启事务。呼叫Open()函数将返回一个IDBOpenDBRequest对象附带一个成功结果result,或者错误消息error,您能够通过事件event来操纵它。IndexedDB中多数其它的异步函数都在做同样的事情——返回一个IDBRequest对象附带一个成功结果result,或者错误消息error。Result是一个IDBDatabase实例。


Open函数的第二个参数是数据库的版本version。数据库的版本决定了数据库的模式——数据库中的对象store和他们的结构。如果数据库不存在,它会被open操作创建,然后触发onupgradeneeded事件,而且您将在该事件句柄中创建数据库模式。如果数据库存在,但是您指定了一个更高的版本,将触发onupgradeneeded事件,然后在该事件句柄中创建数据库模式。更多内容稍后在下面的 Updating the version of the database IDBFactory.open中介绍。


重要:版本号是一个无符号长整型数字,表示它可以是一个很大的数字。不能用浮点型,否则将会被强制转换为最近似

的整型数,而且事务不会开启,upgradeneeded事件不会触发。例如,不要使用2.4作为一个版本号。

var request = indexedDB.open("MyTestDatabase", 2.4);


创建句柄

对于您创建的几乎所有的请求,首先您需要做的是添加success和error句柄:

request.onerror = function(event) {
  // Do something with request.errorCode!
};
request.onsuccess = function(event) {
  // Do something with request.result!
};

onsuccess()和onerror()哪个函数会被调用呢?如果操作成功了,将触发success事件(DOM 事件的属性值为‘success’)

,一旦触发了该事件,request 绑定的onsuccess()函数将被调用,并且把success事件作为参数。反之,如果发生了错误,则按照类型方式,触发error事件,以error事件作为参数调用onerror()函数。

IndexedDB API的设计努力让错误发生降至最少,因此您并不会看到很多的error事件。然而,打开数据库时,通常有一

些情况可能会导致错误发生。最有典型的错误情况是,用户不提供给您web应用许可权来创建数据库。IndexedDB的一个主要设计目标就是为离线应用而存储大量数据。(如需了解每个浏览器的的存储数据容量限制,请参考Storage limits


很明显,浏览器不希望广告网站或者恶意网站充斥于您的电脑,因此,当有web应用为存储数据尝试打开IndexedDB数据库时,第一次浏览器将提示用户。用户可以选择允许或者禁止该行为。而且,浏览器隐私模式下,IndexedDB数据仅仅驻留在内存中,直到匿名模式被关闭(IndexedDB数据才会被存入磁盘)。(Firefox的隐私模式,chrome的匿名模式,但是对于Firefox,截止Nov 2015的版本,隐私模式都是不完善的,因此您无法在Firefox隐私模式下使用IndexedDB)


现在,假设用户允许您申请创建数据库,而且已经收到了成功事件success,并触发了对应函数。接下来要干什么呢,

indexedDB.open()返回了请求request,而request. Result是一个IDBDatabase的实例,您肯定想要保存它。您的代码可能看起来如下:

var db;
var request = indexedDB.open("MyTestDatabase");
request.onerror = function(event) {
  alert("Why didn't you allow my web app to use IndexedDB?!");
};
request.onsuccess = function(event) {
  db = event.target.result;
};

错误处理

如上所述,错误事件冒泡。错误事件绑定在产生错误的request对象上,然后事件冒泡到事务,最终到了数据库对象database。如果您不想为每一个request都添加一个错误事件处理,您可以在数据库对象上添加一个的错误处理,如下

db.onerror = function(event) {
  // Generic error handler for all errors targeted at this database's
  // requests!
  alert("Database error: " + event.target.errorCode);
};

打开数据库时,最常见的错误是VER_ERR,表示已存在数据库的版本号大于指定的数据库版本号,该错误必须被处理

创建数据库或更新数据库版本

当您创建新的数据库或者升级已存在数据库的版本时(在打开数据库时,指定一个更高的版本号数字),onupgradeneeded事件将触发,IDBVersionChangeEvent对象将被传递给任何在request.result上设置的onversionchange事件处理(比如例子中的db)。upgradeneeded 事件处理中,您应该创建对象为该版本的数据库创建对象store

[js]  view plain  copy
  1. // This event is only implemented in recent browsers  
  2. request.onupgradeneeded = function(event) {   
  3.   var db = event.target.result;  
  4.   
  5.   
  6.   // Create an objectStore for this database  
  7.   var objectStore = db.createObjectStore("name", { keyPath: "myKey" });  
  8. };  

此时,数据库中已经拥有了以前版本的数据库的对象store,因此,您无需再创建这些对象store。您唯一需要做的就是

创建新增的对象store,或者删除以前版本中不需要的对象store。如果您需要改变已存在的对象store(比如,keypath)

您必须删除旧的对象store,然后创建新对象store(附带可选项)(注意,此操作将删除原有对象store中的数据,如果你需要这些信息,可以在升级数据库之前,将之读出数据库,保存到合适的位置)。


试图创建已存在的对象store(或者删除不存在的对象store)将引发错误

如果onupgradeneeded事件成功完成,当前的request对应的onsuccess处理程序将被触发

Blink/Webkit 支持当前版本的规范,包括Chrome 23+ 和 Opera17+; IE10+ 也支持。其它的和旧版本不支持当前版本的规范,因此也不支持indexedDB.open(name, version).onupgradeneeded。更多信息关于如何在旧版本Webkit/Blink浏览器升级数据库,请参考IDBDatabasereference article.


数据库结构化

现在介绍数据库结构化。IndexedDB使用对象store而不是表table,一个数据库可以包含任意多个对象store。当一个【值】value被存入对象store时,它总是与一个【键】key关联。根据对象store是使用key path还是keygenerator的情况,

有多种不同的方法提供【键】,下表列出了这些方法:

Key Path (keyPath)

Key Generator (升序)

描述

No

No

对象store可以操纵任何类型的值,包括原生的值比如整数和字符串.一旦您插入新值,您必须提供独立的【键】声明.

Yes

No

对象store只能操纵JavaScript对象. JavaScript对象必须有一个与key path同名的属性.

No

Yes

对象store可以操纵任何类型的值.【键】是自动生成的,或者如果您想自己指定【键】,您可以提供一个独立的【键】声明。

Yes

Yes

对象store只能操纵JavaScript对象。.通常【键】自动产生,它的值存在于对象属性中,与key path同名。但

是,如果这样一个属性已经存在,属性的值将被用于键(即键的值使用现成的),而不是产生一个新的键。



您也可以为任何的对象store创建索引index,提供index对象来操纵对象store,而不是原生的方式。Index让您使用

被存储对象的属性值——而不是对象的【键】——来查询对象store中的值。还有,index可以在存储的数据上实施简

单的约束(constraints)。在创建index时,通过设置唯一标示符unique flag,index可以确保没有任何两个对象在index的key path上的值相同。例如,如果您有一个对象store操纵人口集合,而且您想确保没有任何两个人有相同的email地址,您可以在index设置唯一标示符unique flag来强制这一点。

这听起来有点复杂,但是这个简单的例子应该能解释这个概念。首先,我们定义一些用户数据以备使用:

// This is what our customer data looks like.
const 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" }
];

当然, 您将不会使用某人的社会保障号作为客户表的主键,因为并不是每个人都有社会保障号,而且您将存储他们的

出生日期而不是他们的年龄,这里是为方便起见,请忽略繁琐的细节,把眼光放开。

现在,我们创建数据库。

const dbName = "the_name";

var request = indexedDB.open(dbName, 2);

request.onerror = function(event) {
  // Handle errors.
};
request.onupgradeneeded = function(event) {
  var db = event.target.result;

  // Create an objectStore to hold information about our customers. We're
  // going to use "ssn" as our key path because it's guaranteed to be
  // unique - or at least that's what I was told during the kickoff meeting.
  var objectStore = db.createObjectStore("customers", { keyPath: "ssn" });

  // Create an index to search customers by name. We may have duplicates
  // so we can't use a unique index.
  objectStore.createIndex("name", "name", { unique: false });

  // Create an index to search customers by email. We want to ensure that
  // no two customers have the same email, so use a unique index.
  objectStore.createIndex("email", "email", { unique: true });

  // Use transaction oncomplete to make sure the objectStore creation is 
  // finished before adding data into it.
  objectStore.transaction.oncomplete = function(event) {
    // Store values in the newly created objectStore.
    var customerObjectStore = db.transaction("customers", "readwrite").objectStore("customers");
    for (var i in customerData) {
      customerObjectStore.add(customerData[i]);
    }
  };
};

对象store 通过调用createObjectStore()创建。该方法需要对象store的名字,和一个参数对象。虽然参数对象是可选的,

但是它非常重要,因为可以让您定义重要的可选属性和完善新对象store的类型描述。在我们的例子中,创建了一个对

象store,名字为“customers”,定义了keypath属性,该属性可以让对象store中的对象能够唯一识别,在本例中,该

属性的值是ssn, 因为ssn能够保证唯一性,每一个存入对象store的对象都必须提供ssn。


使用key generator

创建对象store时,设置升序标志autoIncrementflag,能够让激活key generator。默认不设置。

使用key generator,当您向对象store新增数据时,【键】将自动生成。对象store初建时,keygenerator的当前数字是1。

基本上,自动生成的新【键】比前一个【键】多1。keygenerator的当前数字编号从来不会减小,不会因为数据库操作

而恢复。比如,当事务中止。因此,当删除一条记录甚至清空整个对象store,对keygenerator也没有影响。

我们可以用key generator创建另一个对象store:

// Open the indexedDB.
var request = indexedDB.open(dbName, 3);

request.onupgradeneeded = function (event) {

    var db = event.target.result;

    // Create another object store called "names" with the autoIncrement flag set as true.    
    var objStore = db.createObjectStore("names", { autoIncrement : true });

    // Because the "names" object store has the key generator, the key for the name value is generated automatically.
    // The added records would be like:
    // key : 1 => value : "Bill"
    // key : 2 => value : "Donna"
    for (var i in customerData) {
        objStore.add(customerData[i].name);
    }
};
更多key generator的内容,请参考 W3C Key Generators


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值