IndexedDB运用与出坑指南

概述

本文经由过程对IndexedDB的应用要领和应用场景举行相干引见,对罕见的题目举行解答。

同时,因为MDN中的相干文档缺少相干逻辑性,所以不容易明白。本文将经由过程项目中罕见的数据存储和操纵需求来举行内容构造。

读者能够经由过程本文学会在项目中准确的应用IndexedDB,给应用带来的当地存储才能,而且防止一些罕见的题目。

缘由:开辟者须要在当地举行永远存储

当我们举行一些较大的SPA页面开辟时,我们会须要举行一些数据的当地存储。

当数据量不大时,我们能够经由过程SessionStorage或许LocalStorage来举行存储,然则当数据量较大,或相符肯定的范例时,我们能够应用数据库来举行数据的存储。

在浏览器供应的数据库中,共有web sqlIndexedDB两种。相较于HTML5已烧毁的web sql来讲,更引荐人人应用IndexedDB

构造

下面,我们经由过程一张图来相识下,IndexedDB团体的构造。

《IndexedDB运用与出坑指南》

类比sql型数据库,IndexedDB中的DB(数据库)就是sql中的DB,而Object Store(存储空间)则是数据表,Item则即是表中的一条纪录

应用IndexedDB

如今,我们将其依据IndexedDB的构造来对其操纵举行引见,能让人人对这个存储空间有一个开端的相识。我们重要引见:

  • 数据库操纵
  • 数据表操纵
  • 数据操纵

数据库操纵

竖立或翻开数据库

应用IndexedDB第一步,就是竖立或翻开一个数据库。我们应用window.indexedDB.open(DBName)这个API来打举行操纵。详细示例以下:

const request = window.indexedDB.open('test');

request.onupgradeneeded = function (event) {
    
}

request.onsuccess = function(event) {
    //request === event.target;
}
request.onerror = function(event) {}

挪用此接口时,假如当前数据库不存在,则会竖立一个新的数据库。

当数据库竖立衔接时,会返回一个IDBOpenDBRequest对象。

在衔接竖立胜利时,会触发onsuccess事宜,个中函数参数eventtarget属性就是request对象。

而在数据库竖立或许版本更新时,会触发onupgradeneeded事宜。

更新数据库版本号

window.indexedDB.open的第二个参数即为版本号。在不指定的情况下,默许版本号为1。详细示例以下:

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

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

我们须要注重的是,版本号是一个Unsigned long long数字,这意味着它能够是一个非常大的整数。然则,它不能是一个小数,不然它将会被转为近来的整数,同时有能够致使onUpgradeneeded事宜不触发(bug)。

存储空间操纵

竖立存储空间

我们应用createObjectStore来竖立一个存储空间。同时,应用createIndex来竖立它的索引。详细示例以下:

var request = window.indexedDB.open('test', 1);

request.onupgradeneeded = function (event) {
    var db = event.target.result;
    var objectStore = db.createObjectStore('table1', {keyPath: 'id', autoIncrement: true});

    objectStore.createIndex('name', 'name', {unique: false});
}

request.onerror = function (event) {
    alert("Why didn't you allow my web app to use IndexedDB?!");
};

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

经由过程createObjectStore能够竖立一个存储空间。接收两个参数:

  1. 第一个参数,存储空间的称号,即我们上面的customers
  2. 第二个参数,指定存储的keyPath值为存储对象的某个属性,这个属性能够在猎取存储空间数据的时刻当作key值应用。autoIncrement指定了key值是不是自增(当key值为默许的从1最先到2^53的整数时)。

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

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

数据操纵

事件

IndexedDB中,我们也能够应用事件来举行数据库的操纵。事件有三个形式(常量已弃用):

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

我们竖立一个事件时,须要从上面挑选一种形式,假如不指定的话,则默许为只读形式。详细示例以下:

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

事件函数transaction的第一个参数为须要关联的存储空间,第二个可选参数为事件形式。与上面相似,事件胜利时也会触发onsuccess函数,失利时触发onerror函数。

事件的操纵都是原子性的。

增添数据

当存储空间初始化完成后,我们能够把数据放入存储空间中。直接挪用add要领就能够将数据放入存储空间内,详细示例以下:

var request = window.indexedDB.open('test', 1);

request.onsuccess = function (event) {
    var db = event.target.result;

    var transaction = db.transaction(['table1'], 'readwrite');

    var objectStore = transaction.objectStore('table1');

    var index = objectStore.index('name');

    objectStore.add({name: 'a', age: 10});
    objectStore.add({name: 'b', age: 20});
}

注:add要领中的第二个参数key值是指定存储空间中的keyPath值,假如data中包含keyPath值或许此值为自增值,那末能够略去此参数。

查找数据

经由过程特定值猎取数据

当我们须要从存储空间猎取数据时,我们能够经由过程以下的要领:

var request = window.indexedDB.open('test', 1);

request.onsuccess = function (event) {
    var db = event.target.result;

    var transaction = db.transaction(['table1'], 'readwrite');

    var objectStore = transaction.objectStore('table1');

    var request = objectStore.get(1);

    request.onsuccess = function (event) {
        // 对 request.result 做些操纵!
        console.log(request.result);
    };

    request.onerror = function (event) {
        // 毛病处置惩罚!
    };
}

经由过程游标猎取数据

当你须要方便全部存储空间中的数据时,你就须要应用到游标。游标应用要领以下:

var request = window.indexedDB.open('test', 1);

request.onsuccess = function (event) {
    var db = event.target.result;

    var transaction = db.transaction(['table1'], 'readwrite');

    var objectStore = transaction.objectStore('table1');

    var request = objectStore.openCursor();

    request.onsuccess = function (event) {
        var cursor = event.target.result;
        if (cursor) {
            // 应用Object.assign要领是为了防止控制台打印时失足
            console.log(Object.assign(cursor.value));
            cursor.continue();
        }
    };

    request.onerror = function (event) {
        // 毛病处置惩罚!
    };
}

应用游标时有一个须要注重的处所,当游标方便全部存储空间然则并未找到给定前提的值时,依然会触发onsuccess函数。

openCursoropenKeyCursor有两个参数:

  1. 第一个参数,遍历局限,指定游标的接见局限。该局限经由过程一个IDBKeyRange参数的要领来猎取。

    遍历局限参数详细示例以下:

    // 婚配值 key === 1
    const singleKeyRange = IDBKeyRange.only(1);
    
    // 婚配值 key >= 1
    const lowerBoundKeyRange = IDBKeyRange.lowerBound(1);
    
    // 婚配值 key > 1
    const lowerBoundOpenKeyRange = IDBKeyRange.lowerBound(1, true);
    
    // 婚配值 key < 2
    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();
      }
    };

  2. 第二个参数,方便递次,指定游标方便时的递次和处置惩罚雷同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(['table1'], 'readwrite');

    var objectStore = transaction.objectStore('table1');

    var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound(1, false);
    var request = objectStore.openCursor(lowerBoundOpenKeyRange, IDBCursor.PREV);

    request.onsuccess = function (event) {
        var cursor = event.target.result;
        if (cursor) {
            // 应用Object.assign要领是为了防止控制台打印时失足
            console.log(Object.assign(cursor.value));
            cursor.continue();
        }
    };

    request.onerror = function (event) {
        // 毛病处置惩罚!
    };
}

应用索引

在前面构建数据库时,我们竖立了两个索引。如今我们也能够经由过程索引来举行数据检索。他的实质照样经由过程之前猎取数据的API来举行,只是将本来应用的keyPath属性转换成为了索引指定的属性。详细示例以下:

var request = window.indexedDB.open('test', 1);

request.onsuccess = function (event) {
    var db = event.target.result;

    var transaction = db.transaction(['table1'], 'readwrite');

    var objectStore = transaction.objectStore('table1');

    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);
    }
}

修正数据

当须要修正存储空间中的数据时,我们能够应用以下的API:

var objectStore = transaction.objectStore("customers");

var request = objectStore.put(data);

request.onsuccess = function (event) {
    
}

注:put要领不仅能够修正现有数据,也能够往存储空间中增添新的数据。

删除数据

当我们须要删除已无用的数据时,我们能够经由过程以下要领:

var objectStore = transaction.objectStore("customers");

var request = objectStore.delete(name);

request.onsuccess = function (event) {
    
}

非常处置惩罚

在浏览器有以下操纵的情况下,indexedDB能够会涌现非常:

  • 用户消灭浏览器缓存
  • 存储空间凌驾大小限定

此时,须要对毛病举行捕捉,而且对用户举行提醒。此章节不是本文重点,再此略过。

扩大须知

取值相干

key值能够接收的数据范例

IndexedDB中,键值对中的key值能够接收以下几种范例的值:

  • number
  • data
  • string
  • binary
  • array

详细申明能够见文档此处

key path能够接收的数据范例

当一个key值变成主键,即keyPath时,它的值就只能是以下几种:

  • Blob
  • File
  • Array
  • String

注:空格不能出如今key path中

详细申明能够见文档此处

value能够接收的数据范例

IndexedDB中,value能够接收ECMA-262中一切的范例的值,比方String,Date,ImageDate等。

事件相干

事件中缀后,会不会影响key值的自增

IndexedDB在没有指定key值的时刻就会采纳自增的key值。假如一个事件在半途中缀,那末key值的自增将会从中缀的事件最先前的key最先。

平安相干

IndexedDB也遭到浏览器同源战略的限定。

用户相干

清空缓存

用户在消灭浏览器缓存时,能够会消灭IndexedDB中相干的数据。

接见权限

部份浏览器如Safari手机版隐私形式在接见IndexedDB时,能够会涌现因为没有权限而致使的非常(LocalStorage也会),须要举行非常处置惩罚。

总结

IndexedDB在当地存储中有着无可替换的作用,是替换关联型数据库web sql的产物,能够对大批数据举行存储。在很多须要应用离线存储的场景下,它能够给我们供应有用的支持。

然则,IndexedDB在应用过程中依然须要防止能够会涌现的一些题目,或许对能够致使的不利影响有肯定的容错处置惩罚。如许才不会对应用发生严重影响。

参考文献

    原文作者:hjava
    原文地址: https://segmentfault.com/a/1190000006924681
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞