成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

IndexedDB使用與出坑指南

陳偉 / 2742人閱讀

摘要:在不指定的情況下,默認(rèn)版本號(hào)為。具體示例如下在需要更新數(shù)據(jù)庫(kù)的模式時(shí),需要更新版本號(hào)。此時(shí)我們指定一個(gè)高于之前版本的版本號(hào),就會(huì)觸發(fā)事件。數(shù)據(jù)操作事務(wù)在中,我們也能夠使用事務(wù)來(lái)進(jìn)行數(shù)據(jù)庫(kù)的操作。

概述

本文通過(guò)對(duì)IndexedDB的使用方法和使用場(chǎng)景進(jìn)行相關(guān)介紹,對(duì)常見的問(wèn)題進(jìn)行解答。

同時(shí),因?yàn)镸DN中的相關(guān)文檔缺乏相關(guān)邏輯性,所以不容易理解。本文將通過(guò)項(xiàng)目中常見的數(shù)據(jù)存儲(chǔ)和操作需求來(lái)進(jìn)行內(nèi)容組織。

讀者能夠通過(guò)本文學(xué)會(huì)在項(xiàng)目中正確的使用IndexedDB,給應(yīng)用帶來(lái)的本地存儲(chǔ)能力,并且避免一些常見的問(wèn)題。

原因:開發(fā)者需要在本地進(jìn)行永久存儲(chǔ)

當(dāng)我們進(jìn)行一些較大的SPA頁(yè)面開發(fā)時(shí),我們會(huì)需要進(jìn)行一些數(shù)據(jù)的本地存儲(chǔ)。

當(dāng)數(shù)據(jù)量不大時(shí),我們可以通過(guò)SessionStorage或者LocalStorage來(lái)進(jìn)行存儲(chǔ),但是當(dāng)數(shù)據(jù)量較大,或符合一定的規(guī)范時(shí),我們可以使用數(shù)據(jù)庫(kù)來(lái)進(jìn)行數(shù)據(jù)的存儲(chǔ)。

在瀏覽器提供的數(shù)據(jù)庫(kù)中,共有web sqlIndexedDB兩種。相較于HTML5已經(jīng)廢棄的web sql來(lái)說(shuō),更推薦大家使用IndexedDB

結(jié)構(gòu)

下面,我們通過(guò)一張圖來(lái)了解下,IndexedDB整體的結(jié)構(gòu)。

類比sql型數(shù)據(jù)庫(kù),IndexedDB中的DB(數(shù)據(jù)庫(kù))就是sql中的DB,而Object Store(存儲(chǔ)空間)則是數(shù)據(jù)表,Item則等于表中的一條記錄。

使用IndexedDB

現(xiàn)在,我們將其根據(jù)IndexedDB的結(jié)構(gòu)來(lái)對(duì)其操作進(jìn)行介紹,能讓大家對(duì)這個(gè)存儲(chǔ)空間有一個(gè)初步的了解。我們主要介紹:

數(shù)據(jù)庫(kù)操作

數(shù)據(jù)表操作

數(shù)據(jù)操作

數(shù)據(jù)庫(kù)操作 創(chuàng)建或打開數(shù)據(jù)庫(kù)

使用IndexedDB第一步,就是創(chuàng)建或打開一個(gè)數(shù)據(jù)庫(kù)。我們使用window.indexedDB.open(DBName)這個(gè)API來(lái)打進(jìn)行操作。具體示例如下:

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

request.onupgradeneeded = function (event) {
    
}

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

調(diào)用此接口時(shí),如果當(dāng)前數(shù)據(jù)庫(kù)不存在,則會(huì)創(chuàng)建一個(gè)新的數(shù)據(jù)庫(kù)。

當(dāng)數(shù)據(jù)庫(kù)建立連接時(shí),會(huì)返回一個(gè)IDBOpenDBRequest對(duì)象。

在連接建立成功時(shí),會(huì)觸發(fā)onsuccess事件,其中函數(shù)參數(shù)eventtarget屬性就是request對(duì)象。

而在數(shù)據(jù)庫(kù)創(chuàng)建或者版本更新時(shí),會(huì)觸發(fā)onupgradeneeded事件。

更新數(shù)據(jù)庫(kù)版本號(hào)

window.indexedDB.open的第二個(gè)參數(shù)即為版本號(hào)。在不指定的情況下,默認(rèn)版本號(hào)為1。具體示例如下:

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

在需要更新數(shù)據(jù)庫(kù)的schema(模式)時(shí),需要更新版本號(hào)。此時(shí)我們指定一個(gè)高于之前版本的版本號(hào),就會(huì)觸發(fā)onupgradeneeded事件。類似的,當(dāng)此數(shù)據(jù)庫(kù)不存在時(shí),也會(huì)觸發(fā)此事件并且將版本更新到置頂版本。

我們需要注意的是,版本號(hào)是一個(gè)Unsigned long long數(shù)字,這意味著它可以是一個(gè)非常大的整數(shù)。但是,它不能是一個(gè)小數(shù),否則它將會(huì)被轉(zhuǎn)為最近的整數(shù),同時(shí)有可能導(dǎo)致onUpgradeneeded事件不觸發(fā)(bug)。

存儲(chǔ)空間操作 創(chuàng)建存儲(chǔ)空間

我們使用createObjectStore來(lái)創(chuàng)建一個(gè)存儲(chǔ)空間。同時(shí),使用createIndex來(lái)創(chuàng)建它的索引。具體示例如下:

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回調(diào)函數(shù)中創(chuàng)建存儲(chǔ)空間,而不能在數(shù)據(jù)庫(kù)打開后的success回調(diào)函數(shù)中創(chuàng)建。

通過(guò)createObjectStore能夠創(chuàng)建一個(gè)存儲(chǔ)空間。接受兩個(gè)參數(shù):

第一個(gè)參數(shù),存儲(chǔ)空間的名稱,即我們上面的customers。

第二個(gè)參數(shù),指定存儲(chǔ)的keyPath值為存儲(chǔ)對(duì)象的某個(gè)屬性,這個(gè)屬性能夠在獲取存儲(chǔ)空間數(shù)據(jù)的時(shí)候當(dāng)做key值使用。autoIncrement指定了key值是否自增(當(dāng)key值為默認(rèn)的從1開始到2^53的整數(shù)時(shí))。

createIndex能夠給當(dāng)前的存儲(chǔ)空間設(shè)置一個(gè)索引。它接受三個(gè)參數(shù):

第一個(gè)參數(shù),索引的名稱。

第二個(gè)參數(shù),指定根據(jù)存儲(chǔ)數(shù)據(jù)的哪一個(gè)屬性來(lái)構(gòu)建索引。

第三個(gè)屬性, options對(duì)象,其中屬性unique的值為true表示不允許索引值相等。

數(shù)據(jù)操作 事務(wù)

IndexedDB中,我們也能夠使用事務(wù)來(lái)進(jìn)行數(shù)據(jù)庫(kù)的操作。事務(wù)有三個(gè)模式(常量已經(jīng)棄用):

readOnly,只讀。

readwrite,讀寫。

versionchange,數(shù)據(jù)庫(kù)版本變化。

我們創(chuàng)建一個(gè)事務(wù)時(shí),需要從上面選擇一種模式,如果不指定的話,則默認(rèn)為只讀模式。具體示例如下:

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

事務(wù)函數(shù)transaction的第一個(gè)參數(shù)為需要關(guān)聯(lián)的存儲(chǔ)空間,第二個(gè)可選參數(shù)為事務(wù)模式。與上面類似,事務(wù)成功時(shí)也會(huì)觸發(fā)onsuccess函數(shù),失敗時(shí)觸發(fā)onerror函數(shù)。

事務(wù)的操作都是原子性的。

增加數(shù)據(jù)

當(dāng)存儲(chǔ)空間初始化完成后,我們可以把數(shù)據(jù)放入存儲(chǔ)空間中。直接調(diào)用add方法就可以將數(shù)據(jù)放入存儲(chǔ)空間內(nèi),具體示例如下:

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方法中的第二個(gè)參數(shù)key值是指定存儲(chǔ)空間中的keyPath值,如果data中包含keyPath值或者此值為自增值,那么可以略去此參數(shù)。

查找數(shù)據(jù) 通過(guò)特定值獲取數(shù)據(jù)

當(dāng)我們需要從存儲(chǔ)空間獲取數(shù)據(jù)時(shí),我們可以通過(guò)以下的方法:

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) {
        // 對(duì) request.result 做些操作!
        console.log(request.result);
    };

    request.onerror = function (event) {
        // 錯(cuò)誤處理!
    };
}
通過(guò)游標(biāo)獲取數(shù)據(jù)

當(dāng)你需要便利整個(gè)存儲(chǔ)空間中的數(shù)據(jù)時(shí),你就需要使用到游標(biāo)。游標(biāo)使用方法如下:

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方法是為了避免控制臺(tái)打印時(shí)出錯(cuò)
            console.log(Object.assign(cursor.value));
            cursor.continue();
        }
    };

    request.onerror = function (event) {
        // 錯(cuò)誤處理!
    };
}

使用游標(biāo)時(shí)有一個(gè)需要注意的地方,當(dāng)游標(biāo)便利整個(gè)存儲(chǔ)空間但是并未找到給定條件的值時(shí),仍然會(huì)觸發(fā)onsuccess函數(shù)。

openCursoropenKeyCursor有兩個(gè)參數(shù):

第一個(gè)參數(shù),遍歷范圍,指定游標(biāo)的訪問(wèn)范圍。該范圍通過(guò)一個(gè)IDBKeyRange參數(shù)的方法來(lái)獲取。

遍歷范圍參數(shù)具體示例如下:

// 匹配值 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();
  }
};

?

第二個(gè)參數(shù),便利順序,指定游標(biāo)便利時(shí)的順序和處理相同id(keyPath屬性指定字段)重復(fù)時(shí)的處理方法。改范圍通過(guò)特定的字符串(IDBCursor的常量已經(jīng)棄用)來(lái)獲取。其中:

next,從前往后獲取所有數(shù)據(jù)(包括重復(fù)數(shù)據(jù))

prev,從后往前獲取所有數(shù)據(jù)(包括重復(fù)數(shù)據(jù))

nextunique,從前往后獲取數(shù)據(jù)(重復(fù)數(shù)據(jù)只取第一條,索引重復(fù)即認(rèn)為重復(fù),下同)

prevunique,從后往前獲取數(shù)據(jù)(重復(fù)數(shù)據(jù)只取第一條)

遍歷順序參數(shù)具體示例如下:

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方法是為了避免控制臺(tái)打印時(shí)出錯(cuò)
            console.log(Object.assign(cursor.value));
            cursor.continue();
        }
    };

    request.onerror = function (event) {
        // 錯(cuò)誤處理!
    };
}
使用索引

在前面構(gòu)建數(shù)據(jù)庫(kù)時(shí),我們創(chuàng)建了兩個(gè)索引?,F(xiàn)在我們也可以通過(guò)索引來(lái)進(jìn)行數(shù)據(jù)檢索。他的本質(zhì)還是通過(guò)之前獲取數(shù)據(jù)的API來(lái)進(jìn)行,只是將原來(lái)使用的keyPath屬性轉(zhuǎn)換成為了索引指定的屬性。具體示例如下:

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

    // 第二種,普通游標(biāo)方法
    index.openCursor().onsuccess = function (event) {
        console.log("openCursor:", event.target.result.value);
    }

    // 第三種,鍵游標(biāo)方法,該方法與第二種的差別為:普通游標(biāo)帶有value值表示獲取的數(shù)據(jù),而鍵游標(biāo)沒有
    index.openKeyCursor().onsuccess = function (event) {
        console.log("openKeyCursor:", event.target.result);
    }
}
修改數(shù)據(jù)

當(dāng)需要修改存儲(chǔ)空間中的數(shù)據(jù)時(shí),我們可以使用以下的API:

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

var request = objectStore.put(data);

request.onsuccess = function (event) {
    
}

注:put方法不僅能夠修改現(xiàn)有數(shù)據(jù),也能夠往存儲(chǔ)空間中增加新的數(shù)據(jù)。

刪除數(shù)據(jù)

當(dāng)我們需要?jiǎng)h除已經(jīng)無(wú)用的數(shù)據(jù)時(shí),我們可以通過(guò)以下方法:

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

var request = objectStore.delete(name);

request.onsuccess = function (event) {
    
}
異常處理

在瀏覽器有如下操作的情況下,indexedDB可能會(huì)出現(xiàn)異常:

用戶清除瀏覽器緩存

存儲(chǔ)空間超過(guò)大小限制

此時(shí),需要對(duì)錯(cuò)誤進(jìn)行捕獲,并且對(duì)用戶進(jìn)行提示。此章節(jié)不是本文重點(diǎn),再此略過(guò)。

擴(kuò)展須知 取值相關(guān) key值能夠接受的數(shù)據(jù)類型

IndexedDB中,鍵值對(duì)中的key值可以接受以下幾種類型的值:

number

data

string

binary

array

具體說(shuō)明可以見文檔此處。

key path能夠接受的數(shù)據(jù)類型

當(dāng)一個(gè)key值變?yōu)橹麈I,即keyPath時(shí),它的值就只能是以下幾種:

Blob

File

Array

String

注:空格不能出現(xiàn)在key path中

具體說(shuō)明可以見文檔此處。

value能夠接受的數(shù)據(jù)類型

IndexedDB中,value能夠接受ECMA-262中所有的類型的值,例如String,Date,ImageDate等。

事務(wù)相關(guān) 事務(wù)中斷后,會(huì)不會(huì)影響key值的自增

IndexedDB在沒有指定key值的時(shí)候就會(huì)采用自增的key值。如果一個(gè)事務(wù)在中途中斷,那么key值的自增將會(huì)從中斷的事務(wù)開始前的key開始。

安全相關(guān)

IndexedDB也受到瀏覽器同源策略的限制。

用戶相關(guān) 清空緩存

用戶在清除瀏覽器緩存時(shí),可能會(huì)清除IndexedDB中相關(guān)的數(shù)據(jù)。

訪問(wèn)權(quán)限

部分瀏覽器如Safari手機(jī)版隱私模式在訪問(wèn)IndexedDB時(shí),可能會(huì)出現(xiàn)由于沒有權(quán)限而導(dǎo)致的異常(LocalStorage也會(huì)),需要進(jìn)行異常處理。

總結(jié)

IndexedDB在本地存儲(chǔ)中有著無(wú)可替代的作用,是替代關(guān)系型數(shù)據(jù)庫(kù)web sql的產(chǎn)品,能夠?qū)Υ罅繑?shù)據(jù)進(jìn)行存儲(chǔ)。在許多需要運(yùn)用離線存儲(chǔ)的場(chǎng)景下,它能夠給我們提供有效的支撐。

但是,IndexedDB在使用過(guò)程中仍然需要避免可能會(huì)出現(xiàn)的一些問(wèn)題,或者對(duì)可能導(dǎo)致的不利影響有一定的容錯(cuò)處理。這樣才不會(huì)對(duì)應(yīng)用產(chǎn)生重大影響。

參考文獻(xiàn)

瀏覽器的同源策略

使用indexedDB MDN入門

IndexedDB API參考

W3C IndexedDB 2.0規(guī)范

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/80378.html

相關(guān)文章

  • PDO擴(kuò)展PDO::ATTR_AUTOCOMMIT 出坑

    摘要:?jiǎn)栴}描述我自己以擴(kuò)展為基礎(chǔ),封裝了一個(gè)異步任務(wù)服務(wù)器框架,數(shù)據(jù)庫(kù)操作使用擴(kuò)展,但是在插入數(shù)據(jù)的時(shí)候,出現(xiàn)了異常情況,具體狀況如下表引擎的正常插入,沒有問(wèn)題表引擎查詢都可以的,但是插入失敗,出現(xiàn)回滾現(xiàn)象,字段變化,表的變化,正常返回解決過(guò)程監(jiān) 問(wèn)題描述 我自己以swoole擴(kuò)展為基礎(chǔ),封裝了一個(gè)異步任務(wù)服務(wù)器框架,數(shù)據(jù)庫(kù)操作使用pdo擴(kuò)展,但是在插入數(shù)據(jù)的時(shí)候,出現(xiàn)了異常情況,具體狀況如...

    Binguner 評(píng)論0 收藏0
  • 總要先爬出坑的JEE架構(gòu)

    摘要:只要滿足規(guī)范的放入該容器,馬上就會(huì)被容器進(jìn)行高效率的管理。根據(jù)康威定律,設(shè)計(jì)系統(tǒng)的組織時(shí),最終產(chǎn)生的設(shè)計(jì)等價(jià)于組織的溝通結(jié)構(gòu),通俗來(lái)講,團(tuán)隊(duì)的交流機(jī)制應(yīng)該與架構(gòu)分層交互機(jī)制相對(duì)應(yīng)。 本博客 貓叔的博客,轉(zhuǎn)載請(qǐng)申明出處 先來(lái)看看官網(wǎng)對(duì)它的定義。 Java平臺(tái)企業(yè)版(Java EE)是社區(qū)驅(qū)動(dòng)的企業(yè)軟件的標(biāo)準(zhǔn)。Java EE是使用Java Community Process開發(fā)的,其中包括...

    Coding01 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<