本指南說明 IndexedDB API 的基本概念。我們目前使用 Jake Archibald 的 IndexedDB Promised 程式庫,與 IndexedDB API 非常類似,但使用了承諾,您可以await
獲取更簡潔的語法。這樣可簡化 API,同時維持 API 結構。
什麼是 IndexedDB?
IndexedDB 是大規模的 NoSQL 儲存系統,可儲存幾乎所有的使用者瀏覽器內容。除了一般的搜尋、取得和插入動作外,IndexedDB 還支援交易,非常適合儲存大量結構化資料。
每個 IndexedDB 資料庫都專屬於一個「來源」 (通常是網站網域或子網域),這表示其他來源無法存取或存取該資料庫。本身的資料儲存空間限制通常較大,但不同瀏覽器處理限制和資料清除的方式都不同。詳情請參閱「延伸閱讀」一節。
IndexedDB 字詞
- 資料庫
- IndexedDB 的最高層級,這個檔案包含物件儲存空間,其中又包含您要保留的資料。您可以根據自己選擇的名稱建立多個資料庫。
- 物件存放區
- 用於儲存資料的個別值區,類似關聯資料庫中的資料表。一般來說,儲存的每個類型 (非 JavaScript 資料類型) 都會擁有一個物件儲存空間。與資料庫資料表不同的是,儲存庫中的 JavaScript 資料類型不需要保持一致。舉例來說,如果應用程式的
people
物件存放區包含三人的相關資訊,這些使用者的年齡屬性可能是53
、'twenty-five'
和unknown
。 - 索引
- 一種物件存放區,可透過資料的個別屬性整理其他物件存放區 (稱為參照物件存放區) 中的資料。索引可用來擷取這個屬性在物件存放區中的記錄。例如,如果您是養護人員,可能會想稍後再透過姓名、年齡或喜愛的動物來擷取他們。
- 作業
- 與資料庫的互動。
- 交易
- 單一作業或一組作業的包裝函式,確保資料庫完整性。如果交易中的其中一個動作失敗,則不會套用這些動作,資料庫也會回到交易發生之前的狀態。IndexedDB 中的所有讀取或寫入作業都必須屬於交易的一部分。 這樣可以實現不可分割的讀取-修改-寫入作業,而不會與同時處理資料庫的其他執行緒發生衝突。
- 遊標
- 針對資料庫中多個記錄進行疊代的機制。
如何查看 IndexedDB 支援
索引資料庫幾乎全面支援。不過,如果您使用的是舊版瀏覽器,光是設定功能偵測支援就不是個好主意。最簡單的方法是檢查 window
物件:
function indexedDBStuff () {
// Check for IndexedDB support:
if (!('indexedDB' in window)) {
// Can't use IndexedDB
console.log("This browser doesn't support IndexedDB");
return;
} else {
// Do IndexedDB stuff here:
// ...
}
}
// Run IndexedDB code:
indexedDBStuff();
如何開啟資料庫
透過 IndexedDB,您可以使用自己選擇的名稱建立多個資料庫。如果嘗試開啟資料庫時不存在,系統會自動建立資料庫。如要開啟資料庫,請使用 idb
程式庫中的 openDB()
方法:
import {openDB} from 'idb';
async function useDB () {
// Returns a promise, which makes `idb` usable with async-await.
const dbPromise = await openDB('example-database', version, events);
}
useDB();
這個方法會傳回一個承諾,該承諾會解析為資料庫物件。使用 openDB()
方法時,請提供名稱、版本編號和用來設定資料庫的事件物件。
以下是結構定義中的 openDB()
方法範例:
import {openDB} from 'idb';
async function useDB () {
// Opens the first version of the 'test-db1' database.
// If the database does not exist, it will be created.
const dbPromise = await openDB('test-db1', 1);
}
useDB();
將檢查索引資料庫支援的檢查置於匿名函式的頂端。如果瀏覽器不支援 IndexedDB,這麼做會結束函式。如果函式可以繼續,就會呼叫 openDB()
方法開啟名為 'test-db1'
的資料庫。本範例中,為了簡化作業,系統省略了選用的事件物件,但您必須指定該物件才能執行 IndexedDB 任何有意義的工作。
如何使用物件存放區
IndexedDB 資料庫包含一或多個「物件存放區」,每個物件存放區包含一個索引鍵資料欄,以及另一個用於該鍵相關資料的資料欄。
建立物件存放區
結構良好的 IndexedDB 資料庫應針對各種需要保留的資料提供一個物件存放區。舉例來說,保留使用者個人資料和附註的網站可能會有包含 person
物件的 people
物件存放區,以及包含 note
物件的 notes
物件存放區。
為確保資料庫完整性,您只能透過 openDB()
呼叫的事件物件建立或移除物件存放區。事件物件會公開 upgrade()
方法,方便您建立物件儲存庫。在 upgrade()
方法中呼叫 createObjectStore()
方法,建立物件儲存庫:
import {openDB} from 'idb';
async function createStoreInDB () {
const dbPromise = await openDB('example-database', 1, {
upgrade (db) {
// Creates an object store:
db.createObjectStore('storeName', options);
}
});
}
createStoreInDB();
此方法會使用物件存放區的名稱,以及可定義物件存放區的各種屬性的選用設定物件。
以下為如何使用 createObjectStore()
的範例:
import {openDB} from 'idb';
async function createStoreInDB () {
const dbPromise = await openDB('test-db1', 1, {
upgrade (db) {
console.log('Creating a new object store...');
// Checks if the object store exists:
if (!db.objectStoreNames.contains('people')) {
// If the object store does not exist, create it:
db.createObjectStore('people');
}
}
});
}
createStoreInDB();
在此範例中,事件物件會傳遞至 openDB()
方法來建立物件存放區,和先前一樣,建立物件儲存庫的工作則在事件物件的 upgrade()
方法中完成。但是,由於如果您嘗試建立現有的物件存放區,瀏覽器會擲回錯誤,因此建議您將 createObjectStore()
方法納入 if
陳述式,檢查物件存放區是否存在。在 if
區塊中,呼叫 createObjectStore()
以建立名為 'firstOS'
的物件儲存庫。
如何定義主鍵
定義物件存放區時,您可以使用主鍵定義資料在儲存庫中唯一識別的方式。您可以定義金鑰路徑或使用金鑰產生器,定義主鍵。
「鍵路徑」是始終存在的屬性,且包含不重複的值。舉例來說,如果是 people
物件存放區,您可以選擇電子郵件地址做為金鑰路徑:
import {openDB} from 'idb';
async function createStoreInDB () {
const dbPromise = await openDB('test-db2', 1, {
upgrade (db) {
if (!db.objectStoreNames.contains('people')) {
db.createObjectStore('people', { keyPath: 'email' });
}
}
});
}
createStoreInDB();
本範例建立名為 'people'
的物件存放區,並在 keyPath
選項中指派 email
屬性做為主鍵。
您也可以使用金鑰產生器,例如 autoIncrement
。金鑰產生器會為物件存放區的每個新增物件建立不重複的值。根據預設,如果您沒有指定鍵,IndexedDB 會建立金鑰,並將其與資料分開儲存。
以下範例會建立名為 'notes'
的物件儲存庫,並將主鍵設定為自動遞增編號:
import {openDB} from 'idb';
async function createStoreInDB () {
const dbPromise = await openDB('test-db2', 1, {
upgrade (db) {
if (!db.objectStoreNames.contains('notes')) {
db.createObjectStore('notes', { autoIncrement: true });
}
}
});
}
createStoreInDB();
以下範例與上一個範例類似,但這次自動遞增值已明確指派給名為 'id'
的屬性。
import {openDB} from 'idb';
async function createStoreInDB () {
const dbPromise = await openDB('test-db2', 1, {
upgrade (db) {
if (!db.objectStoreNames.contains('logs')) {
db.createObjectStore('logs', { keyPath: 'id', autoIncrement: true });
}
}
});
}
createStoreInDB();
請依據您的資料選擇用於定義鍵的方法。如果資料有一個始終不重複的屬性,您可以將該屬性設為 keyPath
以強制執行不重複性。否則,請使用自動遞增的值。
下列程式碼會建立三個物件儲存空間,示範在物件存放區中定義主鍵的各種方式:
import {openDB} from 'idb';
async function createStoresInDB () {
const dbPromise = await openDB('test-db2', 1, {
upgrade (db) {
if (!db.objectStoreNames.contains('people')) {
db.createObjectStore('people', { keyPath: 'email' });
}
if (!db.objectStoreNames.contains('notes')) {
db.createObjectStore('notes', { autoIncrement: true });
}
if (!db.objectStoreNames.contains('logs')) {
db.createObjectStore('logs', { keyPath: 'id', autoIncrement: true });
}
}
});
}
createStoresInDB();
如何定義索引
索引是一種物件存放區,可以依指定屬性從參照物件存放區擷取資料。索引位於參照物件儲存庫內,且包含相同資料,但會使用指定的屬性做為金鑰路徑,而非參照存放區的主鍵。建立物件儲存區時必須建立索引,且可用來定義資料的唯一限制。
如要建立索引,請在物件儲存例項上呼叫 createIndex()
方法:
import {openDB} from 'idb';
async function createIndexInStore() {
const dbPromise = await openDB('storeName', 1, {
upgrade (db) {
const objectStore = db.createObjectStore('storeName');
objectStore.createIndex('indexName', 'property', options);
}
});
}
createIndexInStore();
這個方法會建立並傳回索引物件。物件儲存區執行個體的 createIndex()
方法會使用新索引的名稱做為第一個引數,第二個引數則參照要建立索引的資料屬性。最後一個引數可讓您定義兩個選項,以決定索引的運作方式:unique
和 multiEntry
。如果 unique
設為 true
,則索引不允許單一索引鍵使用重複的值。接下來,multiEntry
會決定 createIndex()
在已建立索引的屬性是陣列時的行為。如果設為 true
,createIndex()
會針對每個陣列元素在索引中加入一個項目。否則,會新增一個包含陣列的項目。
範例如下:
import {openDB} from 'idb';
async function createIndexesInStores () {
const dbPromise = await openDB('test-db3', 1, {
upgrade (db) {
if (!db.objectStoreNames.contains('people')) {
const peopleObjectStore = db.createObjectStore('people', { keyPath: 'email' });
peopleObjectStore.createIndex('gender', 'gender', { unique: false });
peopleObjectStore.createIndex('ssn', 'ssn', { unique: true });
}
if (!db.objectStoreNames.contains('notes')) {
const notesObjectStore = db.createObjectStore('notes', { autoIncrement: true });
notesObjectStore.createIndex('title', 'title', { unique: false });
}
if (!db.objectStoreNames.contains('logs')) {
const logsObjectStore = db.createObjectStore('logs', { keyPath: 'id', autoIncrement: true });
}
}
});
}
createIndexesInStores();
在這個範例中,'people'
和 'notes'
物件存放區具有索引。如要建立索引,請先將 createObjectStore()
的結果 (物件儲存物件) 指派給變數,以便對變數呼叫 createIndex()
。
如何使用資料
本節說明如何建立、讀取、更新及刪除資料。這些作業都是非同步的,使用 IndexedDB API 提出要求時就會進行承諾。這樣可以簡化 API。與其監聽要求觸發的事件,您可以在從 openDB()
方法傳回的資料庫物件上呼叫 .then()
,以便開始與資料庫互動,或對其建立 await
。
IndexedDB 中的所有資料作業都是在交易中執行。每項作業的形式如下:
- 取得資料庫物件。
- 在資料庫上開啟交易。
- 開啟交易的物件存放區。
- 在物件存放區執行作業。
交易可視為單一作業或一組作業的安全包裝函式。如果交易中的其中一個動作失敗,所有動作都會復原。交易是針對一或多個物件存放區,您可以在開啟交易時定義的物件存放區。其中有唯讀或讀取/寫入權限這表示交易內的作業會讀取資料或對資料庫進行變更。
建立資料
如要建立資料,請對資料庫例項呼叫 add()
方法,然後傳入要新增的資料。add()
方法的第一個引數是要新增資料的物件存放區,第二個引數則是包含您要新增欄位和相關資料的物件。以下是最簡單的範例,新增一列資料:
import {openDB} from 'idb';
async function addItemToStore () {
const db = await openDB('example-database', 1);
await db.add('storeName', {
field: 'data'
});
}
addItemToStore();
每次 add()
呼叫都會在交易中進行,因此即使承諾可以成功解決,也不一定代表作業有效。如要確認新增作業執行,您必須使用 transaction.done()
方法檢查整個交易是否完成。這個承諾會在交易本身完成時解決,如果交易發生錯誤,便會拒絕。您必須為所有「寫入」作業執行這項檢查,因為這是知道資料庫變更實際已發生的唯一方式。
以下程式碼顯示如何在交易中使用 add()
方法:
import {openDB} from 'idb';
async function addItemsToStore () {
const db = await openDB('test-db4', 1, {
upgrade (db) {
if (!db.objectStoreNames.contains('foods')) {
db.createObjectStore('foods', { keyPath: 'name' });
}
}
});
// Create a transaction on the 'foods' store in read/write mode:
const tx = db.transaction('foods', 'readwrite');
// Add multiple items to the 'foods' store in a single transaction:
await Promise.all([
tx.store.add({
name: 'Sandwich',
price: 4.99,
description: 'A very tasty sandwich!',
created: new Date().getTime(),
}),
tx.store.add({
name: 'Eggs',
price: 2.99,
description: 'Some nice eggs you can cook up!',
created: new Date().getTime(),
}),
tx.done
]);
}
addItemsToStore();
開啟資料庫 (並視需要建立物件存放區) 後,您必須對資料庫呼叫 transaction()
方法來開啟交易。這個方法會接收您要交易的商店及其模式的引數。在本範例中,我們想要寫入儲存庫,因此這個範例指定 'readwrite'
。
下一步是在交易中開始將商品新增至商店。在上述範例中,我們正在處理 'foods'
儲存庫中的三項作業,這些作業每次都會傳回一個承諾:
- 正在新增美味三明治的記錄。
- 正在新增一些雞蛋的記錄。
- 表示交易已完成 (
tx.done
)。
由於這些行動都是基於承諾的,我們需要等待所有這些動作完成。將這些承諾傳遞給 Promise.all
是很好、符合人體工學的方式,可達到做到這點。Promise.all
會接受一系列承諾,並在傳遞的所有承諾項目中完成時結束。
對於要新增的兩筆記錄,交易執行個體的 store
介面會呼叫 add()
,並將資料傳送至該記錄。您可以將 Promise.all
呼叫設為 await
,這樣就會在交易完成時完成。
讀取資料
如要讀取資料,請在使用 openDB()
方法擷取的資料庫例項上呼叫 get()
方法。get()
會使用儲存庫名稱和您要擷取物件的主鍵值。基本範例如下:
import {openDB} from 'idb';
async function getItemFromStore () {
const db = await openDB('example-database', 1);
// Get a value from the object store by its primary key value:
const value = await db.get('storeName', 'unique-primary-key-value');
}
getItemFromStore();
和 add()
一樣,get()
方法會傳回一個承諾,因此您可以視需要 await
使用該項目,或使用承諾的 .then()
回呼。
以下範例使用 'test-db4'
資料庫 'foods'
物件儲存庫上的 get()
方法,透過 'name'
主鍵取得單一資料列:
import {openDB} from 'idb';
async function getItemFromStore () {
const db = await openDB('test-db4', 1);
const value = await db.get('foods', 'Sandwich');
console.dir(value);
}
getItemFromStore();
從資料庫擷取單一資料列的方法相當簡單:開啟資料庫,並為要從資料取得的資料列中指定物件存放區和主鍵值。get()
方法會傳回承諾,因此您可以 await
。
更新資料
如要更新資料,請在物件存放區上呼叫 put()
方法。put()
方法與 add()
方法類似,也可以用來取代 add()
以建立資料。以下是使用 put()
依主鍵值更新物件存放區中資料列的基本範例:
import {openDB} from 'idb';
async function updateItemInStore () {
const db = await openDB('example-database', 1);
// Update a value from in an object store with an inline key:
await db.put('storeName', { inlineKeyName: 'newValue' });
// Update a value from in an object store with an out-of-line key.
// In this case, the out-of-line key value is 1, which is the
// auto-incremented value.
await db.put('otherStoreName', { field: 'value' }, 1);
}
updateItemInStore();
與其他方法一樣,此方法會傳回 promise。也可以在交易中使用 put()
。以下是使用前述 'foods'
商店的範例,該商店會更新三明治和雞蛋的價格:
import {openDB} from 'idb';
async function updateItemsInStore () {
const db = await openDB('test-db4', 1);
// Create a transaction on the 'foods' store in read/write mode:
const tx = db.transaction('foods', 'readwrite');
// Update multiple items in the 'foods' store in a single transaction:
await Promise.all([
tx.store.put({
name: 'Sandwich',
price: 5.99,
description: 'A MORE tasty sandwich!',
updated: new Date().getTime() // This creates a new field
}),
tx.store.put({
name: 'Eggs',
price: 3.99,
description: 'Some even NICER eggs you can cook up!',
updated: new Date().getTime() // This creates a new field
}),
tx.done
]);
}
updateItemsInStore();
項目更新方式取決於您設定金鑰的方式。如果您設定 keyPath
,物件存放區中的每一列都會與內嵌鍵建立關聯。上述範例會根據這個索引鍵更新資料列,而在這種情況下,如果您要更新資料列,就需要指定該鍵,以更新物件存放區中的適當項目。您也可以將 autoIncrement
設為主鍵,藉此建立行外鍵。
刪除資料
如要刪除資料,請在物件儲存庫上呼叫 delete()
方法:
import {openDB} from 'idb';
async function deleteItemFromStore () {
const db = await openDB('example-database', 1);
// Delete a value
await db.delete('storeName', 'primary-key-value');
}
deleteItemFromStore();
和 add()
和 put()
一樣,您可以在交易中使用以下程式碼:
import {openDB} from 'idb';
async function deleteItemsFromStore () {
const db = await openDB('test-db4', 1);
// Create a transaction on the 'foods' store in read/write mode:
const tx = db.transaction('foods', 'readwrite');
// Delete multiple items from the 'foods' store in a single transaction:
await Promise.all([
tx.store.delete('Sandwich'),
tx.store.delete('Eggs'),
tx.done
]);
}
deleteItemsFromStore();
資料庫互動的結構與其他作業相同。請記得在傳遞至 Promise.all
的陣列中加入 tx.done
方法,檢查整個交易是否已完成。
取得所有資料
到目前為止,您一次只從商店擷取一個物件。您也可以使用 getAll()
方法或遊標,從物件存放區或索引擷取所有資料或子集。
getAll()
方法
如要擷取物件儲存的所有資料,最簡單的方法是在物件存放區或索引呼叫 getAll()
,如下所示:
import {openDB} from 'idb';
async function getAllItemsFromStore () {
const db = await openDB('test-db4', 1);
// Get all values from the designated object store:
const allValues = await db.getAll('storeName');
console.dir(allValues);
}
getAllItemsFromStore();
這個方法會傳回物件存放區中的所有物件,沒有任何限制。這是從物件存放區取得所有值最直接的方式,但也最缺乏彈性。
import {openDB} from 'idb';
async function getAllItemsFromStore () {
const db = await openDB('test-db4', 1);
// Get all values from the designated object store:
const allValues = await db.getAll('foods');
console.dir(allValues);
}
getAllItemsFromStore();
以下範例會呼叫 'foods'
物件存放區上的 getAll()
。這會傳回 'foods'
中的所有物件,並依主鍵排序。
如何使用遊標
遊標可讓您更靈活地擷取多個物件。遊標會選取物件存放區中的每個物件,或逐一建立索引,方便您在選取資料時對資料執行操作。如同其他資料庫作業,遊標適用於交易。
如要建立遊標,請在物件存放區上呼叫 openCursor()
做為交易的一部分。使用先前範例中的 'foods'
儲存庫,以下說明如何將遊標移到物件儲存庫中的所有資料列:
import {openDB} from 'idb';
async function getAllItemsFromStoreWithCursor () {
const db = await openDB('test-db4', 1);
const tx = await db.transaction('foods', 'readonly');
// Open a cursor on the designated object store:
let cursor = await tx.store.openCursor();
// Iterate on the cursor, row by row:
while (cursor) {
// Show the data in the row at the current cursor position:
console.log(cursor.key, cursor.value);
// Advance the cursor to the next row:
cursor = await cursor.continue();
}
}
getAllItemsFromStoreWithCursor();
在此情況下,交易會以 'readonly'
模式開啟,並呼叫其 openCursor
方法。在後續的 while
迴圈中,遊標目前位置的資料列可能會讀取其 key
和 value
屬性,並以最適合應用程式的方式處理這些值。準備就緒時,您可以呼叫 cursor
物件的 continue()
方法前往下一個資料列,當遊標到達資料集結尾時,while
迴圈就會終止。
使用含有範圍和索引的遊標
索引可讓您依據主鍵以外的屬性,擷取物件存放區中的資料。您可以在任何屬性上建立索引,該屬性會成為索引的 keyPath
,然後指定該屬性的範圍,然後使用 getAll()
或遊標取得該範圍中的資料。
請使用 IDBKeyRange
物件和下列任一方法定義範圍:
upperBound()
.lowerBound()
.bound()
(兩者皆使用)。only()
.includes()
.
upperBound()
和 lowerBound()
方法會指定範圍的上下限。
IDBKeyRange.lowerBound(indexKey);
或:
IDBKeyRange.upperBound(indexKey);
每個引數都會使用一個引數:您要指定為上限或下限的項目之索引的 keyPath
值。
bound()
方法會指定上限和下限:
IDBKeyRange.bound(lowerIndexKey, upperIndexKey);
根據預設,這些函式的範圍含括在內,也就是包含指定做為範圍限制的資料。如要排除這些值,請將 true
做為 lowerBound()
或 upperBound()
的第二個引數傳遞 true
,或是分別做為 bound()
的第三和第四個引數,分別指定範圍為「專屬」範圍。
下一個範例使用 'foods'
物件存放區中 'price'
屬性的索引。現在,儲存庫也已經附加一份表單,其中包含範圍上下限和下限的兩個輸入內容。請使用以下程式碼,找出價格介於這些上限之間的食物:
import {openDB} from 'idb';
async function searchItems (lower, upper) {
if (!lower === '' && upper === '') {
return;
}
let range;
if (lower !== '' && upper !== '') {
range = IDBKeyRange.bound(lower, upper);
} else if (lower === '') {
range = IDBKeyRange.upperBound(upper);
} else {
range = IDBKeyRange.lowerBound(lower);
}
const db = await openDB('test-db4', 1);
const tx = await db.transaction('foods', 'readonly');
const index = tx.store.index('price');
// Open a cursor on the designated object store:
let cursor = await index.openCursor(range);
if (!cursor) {
return;
}
// Iterate on the cursor, row by row:
while (cursor) {
// Show the data in the row at the current cursor position:
console.log(cursor.key, cursor.value);
// Advance the cursor to the next row:
cursor = await cursor.continue();
}
}
// Get items priced between one and four dollars:
searchItems(1.00, 4.00);
範例程式碼會先取得限制的值,並檢查限制是否存在。接下來的程式碼區塊會根據值決定使用哪種方法來限制範圍。在資料庫互動中,照常在交易中開啟物件存放區,然後在物件儲存庫上開啟 'price'
索引。'price'
索引可讓您依價格搜尋項目。
程式碼隨即會在索引上開啟遊標,並傳入範圍。遊標會傳回代表範圍內第一個物件的承諾,或者如果範圍內沒有資料,則傳回 undefined
。cursor.continue()
方法會傳回代表下一個物件的遊標,並且持續執行迴圈,直到觸及範圍結束為止。
資料庫版本管理
呼叫 openDB()
方法時,您可以在第二個參數中指定資料庫版本號碼。本指南的所有範例均將該版本設為 1
,但如果您需要透過某種方式進行修改,可將資料庫升級至新版本。如果指定的版本大於現有資料庫的版本,系統會執行事件物件中的 upgrade
回呼,讓您可以在資料庫中新增物件存放區和索引。
upgrade
回呼中的 db
物件具有特殊的 oldVersion
屬性,表示瀏覽器可存取的資料庫版本號碼。您可以將這個版本號碼傳遞至 switch
陳述式,根據現有的資料庫版本號碼,在 upgrade
回呼中執行程式碼區塊。範例如下:
import {openDB} from 'idb';
const db = await openDB('example-database', 2, {
upgrade (db, oldVersion) {
switch (oldVersion) {
case 0:
// Create first object store:
db.createObjectStore('store', { keyPath: 'name' });
case 1:
// Get the original object store, and create an index on it:
const tx = await db.transaction('store', 'readwrite');
tx.store.createIndex('name', 'name');
}
}
});
這個範例會將資料庫的最新版本設為 2
。初次執行這段程式碼時,瀏覽器中尚未存在資料庫,因此 oldVersion
是 0
,而 switch
陳述式從 case 0
開始。在這個範例中,這會將 'store'
物件存放區新增至資料庫。
重點提示:在 switch
陳述式中,每個 case
區塊之後通常會有 break
,但這刻意不在這裡使用。這樣一來,如果現有的資料庫落後幾個版本或不存在版本,程式碼便會繼續執行其餘 case
版本,直到更新到最新版本為止。因此,在範例中,瀏覽器會繼續透過 case 1
執行,並在 store
物件儲存庫上建立 name
索引。
如要在 'store'
物件儲存庫上建立 'description'
索引,請更新版本號碼,並新增 case
區塊,如下所示:
import {openDB} from 'idb';
const db = await openDB('example-database', 3, {
upgrade (db, oldVersion) {
switch (oldVersion) {
case 0:
// Create first object store:
db.createObjectStore('store', { keyPath: 'name' });
case 1:
// Get the original object store, and create an index on it:
const tx = await db.transaction('store', 'readwrite');
tx.store.createIndex('name', 'name');
case 2:
const tx = await db.transaction('store', 'readwrite');
tx.store.createIndex('description', 'description');
}
}
});
如果您在上一個範例中建立的資料庫仍存在於瀏覽器中,則執行時,oldVersion
為 2
。瀏覽器會略過 case 0
和 case 1
,並在 case 2
中執行程式碼,進而建立 description
索引。之後,瀏覽器就會擁有第 3 版的資料庫,其中包含包含 name
和 description
索引的 store
物件存放區。
其他資訊
下列資源提供了使用 IndexedDB 的詳細資訊和背景資訊。