IndexedDB 的完整使用指南
原文作者:Chibuike Nwachukwu
原文地址:https://blog.logrocket.com/using-indexeddb-complete-guide/
翻譯:一川
1 寫在前面
數據存儲是大多數 Web
應用程序的重要組成部分,從跟蹤用戶數據到應用程序數據。隨着更快、更強大的Web
應用程序的快速開發,需要高效的客戶端存儲來幫助開發。
多年來,Web
上的客戶端存儲已經發生了很大的變化,從用於存儲用戶數據的 cookie
到 WebSQL
(目前已棄用)的出現,它允許開發人員將數據存儲在瀏覽器中的 SQL
數據庫中,進而允許熟悉SQL
的用戶輕鬆構建健壯的應用程序。
IndexedDB
是WebSQL
的替代品,提供比以前的同類產品更多的存儲容量。在本教程中,我們將探討如何使用和設置 IndexedDB
進行 Web
應用程序數據存儲,以及如何使用可用的 API
操作其數據。
2 什麼是 IndexedDB
?
IndexedDB
是用於客戶端存儲的低級 API
。它是一個成熟的、持久的 NoSQL
存儲系統,可在瀏覽器中使用,允許存儲不同類型的數據,例如:
-
文件或 Blob
-
圖片和視頻
-
結構化數據,如對象、列表和數組
IndexedDB
可用於各種場景,例如緩存、PWA
、遊戲等,並且還支持事務。它的開發是爲了有效地滿足 Web
應用程序的多種需求。
3 設置我們的項目
我們不會做任何花哨的設置,因爲IndexedDB
在網絡上本地運行。首先,創建一個新目錄來容納項目:
mkdir indexed-db && cd indexed-db
現在,我們將創建一個文件來查看我們的應用程序,創建一個index.js
腳本 index.html
文件來存儲我們的應用程序邏輯:
touch index.html index.js styles.css
4 將數據保存到索引數據庫
若要了解使用此數據庫的好處並瞭解如何與 API
交互,我們將創建一個基本的待辦事項應用程序。我們啓用一個添加功能以查看如何將數據保存到數據庫,另一個功能用於查看所有待辦事項,以及一個刪除功能以查看 API
的 GET
和 DELETE
函數。
打開在上一節中創建的,index.html
並添加以下代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta >
<title>TODO APP</title>
<script src="index.js" defer></script>
<link href="style.css" rel="stylesheet">
</head>
<body>
<h1>TODO APP</h1>
<section>
<aside class="view">
<h2>TODOs</h2>
<div class="todos">
<ol></ol>
</div>
</aside>
<aside class="add">
<h2>Add Todo</h2>
<form>
<div>
<label for="title">Todo title</label>
<input id="title" type="text" required>
</div>
<div>
<label for="desc">Todo description</label>
<input id="desc" type="text" required>
</div>
<div>
<button>Save</button>
</div>
</form>
</aside>
</section>
</body>
</html>
這將創建我們的 Web
應用程序的基礎結構。我們在這裏做兩件主要的事情:首先,我們創建一個部分來顯示 / 查看保存在數據庫中的所有待辦事項,其次,我們創建一個用於向數據庫添加待辦事項的部分。
我們還向應用程序添加一些基本樣式。打開styles.css
文件並添加以下內容:
html {
font-family: sans-serif;
}
body {
margin: 0 auto;
max-width: 800px;
}
header, footer {
background-color: blue;
color: white;
padding: 0 20px;
}
.add, .view {
padding: 30px;
width: 40%;
}
.add {
background: #ebe6e6;
}
section {
padding: 10px;
background: #3182d4;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}
h1 {
margin: 0;
}
ol {
list-style-type: none;
}
div {
margin-bottom: 10px;
}
該文件 index.js
是應用程序的核心,因爲它包含用於在應用程序和 IndexedDB
之間進行交互的邏輯。
首先,我們需要創建數據庫;然後,我們可以通過創建一個對象存儲(類似於 SQL
中的表)來初始化它,我們將使用它來存儲每個項目的詳細信息。打開 index.js
該文件並向其添加以下邏輯:
let db;
const openOrCreateDB = window.indexedDB.open('todo_db', 1);
openOrCreateDB.addEventListener('error', () => console.error('Error opening DB'));
openOrCreateDB.addEventListener('success', () => {
console.log('Successfully opened DB');
db = openOrCreateDB.result;
});
openOrCreateDB.addEventListener('upgradeneeded', init => {
db = init.target.result;
db.onerror = () => {
console.error('Error loading database.');
};
const table = db.createObjectStore('todo_tb', { keyPath: 'id', autoIncrement:true });
table.createIndex('title', 'title', { unique: false });
table.createIndex('desc', 'desc', { unique: false });
});
如上所示,創建了一個名爲的數據庫,然後創建了一個名爲 todo_db
的對象存儲,其中包含兩個索引, title
以及desc
。這些索引允許在存儲中複製其值,這類似於在 SQL
中創建表,然後創建兩列。
接下來,要添加 Save
功能,我們繼續檢索輸入到表單中的值,然後將它們保存到數據庫中:
const todos = document.querySelector('ol');
const form = document.querySelector('form');
const todoTitle = document.querySelector('#title');
const todoDesc = document.querySelector('#desc');
const submit = document.querySelector('button');
form.addEventListener('submit', addTodo);
function addTodo(e) {
e.preventDefault();
const newTodo = { title: todoTitle.value, body: todoDesc.value };
const transaction = db.transaction(['todo_tb'], 'readwrite');
const objectStore = transaction.objectStore('todo_tb');
const query = objectStore.add(newTodo);
query.addEventListener('success', () => {
todoTitle.value = '';
todoDesc.value = '';
});
transaction.addEventListener('complete', () => {
showTodos();
});
transaction.addEventListener('error', () => console.log('Transaction error'));
}
將值添加到存儲後,將清空兩個表單字段,以便用戶可以在其列表中輸入新項目。我們可以通過調用 showTodos
方法來更新視圖,我們將在下一節中看到。
5 檢索和顯示數據
要確認保存待辦事項功能是否有效,請打開並使用瀏覽器的檢查功能。在Chrome
中,您可以在 “應用程序” 選項卡下的 “存儲” 中看到 IndexedDB
。如下圖所示,我們創建了數據庫並將第一個待辦事項保存到對象存儲中 todo_tb
:
爲了在用戶加載頁面時顯示可用的待辦事項,並提供以前添加和刪除的待辦事項的視圖,我們將創建一個名爲 showTodos
的方法:
function showTodos() {
while (todos.firstChild) {
todos.removeChild(todos.firstChild);
}
const objectStore = db.transaction('todo_tb').objectStore('todo_tb');
objectStore.openCursor().addEventListener('success', e => {
const pointer = e.target.result;
if(pointer) {
const listItem = document.createElement('li');
const h3 = document.createElement('h3');
const pg = document.createElement('p');
listItem.appendChild(h3);
listItem.appendChild(pg);
todos.appendChild(listItem);
h3.textContent = pointer.value.title;
pg.textContent = pointer.value.body;
listItem.setAttribute('data-id', pointer.value.id);
const deleteBtn = document.createElement('button');
listItem.appendChild(deleteBtn);
deleteBtn.textContent = 'Remove';
deleteBtn.addEventListener('click', deleteItem);
pointer.continue();
} else {
if(!todos.firstChild) {
const listItem = document.createElement('li');
listItem.textContent = 'No Todo.'
todos.appendChild(listItem);
}
console.log('Todos all shown');
}
});
}
此方法從存儲中獲取待辦事項,循環遍歷每個項目,併爲每個項目創建一個 HTML
元素。它將項目追加到網頁上的ol
列表元素,並將每個待辦事項 id
的 傳遞給名爲 data-id
的數據屬性。稍後,當我們介紹該 deleteItem
函數時,我們將使用此唯一ID
來標識每個待辦事項,當我們需要將其從存儲中刪除時。
若要在頁面加載時獲取待辦事項,請將 openOrCreateDB
成功事件偵聽器修改爲:
openOrCreateDB.addEventListener('success', () => {
console.log('Successfully opened DB');
db = openOrCreateDB.result;
showTodos();
});
6 從數據庫中刪除數據
最後,讓我們測試此數據庫的 DELETE API
,併爲我們的待辦事項列表應用創建一個 Delete
函數:
function deleteItem(e) {
const todoId = Number(e.target.parentNode.getAttribute('data-id'));
const transaction = db.transaction(['todo_tb'], 'readwrite');
const objectStore = transaction.objectStore('todo_tb');
objectStore.delete(todoId);
transaction.addEventListener('complete', () => {
e.target.parentNode.parentNode.removeChild(e.target.parentNode);
alert(`Todo with id of ${todoId} deleted`)
console.log(`Todo:${todoId} deleted.`);
if(!todos.firstChild) {
const listItem = document.createElement('li');
listItem.textContent = 'No Todo.';
todos.appendChild(listItem);
}
});
transaction.addEventListener('error', () => console.log('Transaction error'));
}
這會使用傳遞給方法的唯一ID
刪除特定的待辦事項,並從網頁中刪除該元素。刪除存儲中的最後一個待辦事項後,它會在待辦事項列表的位置顯示 “無待辦事項” 消息。
要確認待辦事項已從數據庫中刪除,請繼續檢查網頁並單擊應用程序選項卡。可以看出,todo_tb
對象存儲現在不包含任何項目:
最終的 Web
應用程序如下所示:
7 遞增索引數據庫版本
IndexedDB 還允許開發人員遞增數據庫版本。打開數據庫時,請指定所需的版本號:
window.indexedDB.open('todo_db', 1);
如果數據庫不存在,則將使用指定的版本創建該數據庫。如果數據庫已存在,則檢查版本號。
如果在open
方法調用期間指定的版本號高於現有版本,則會通過該onUpgradeNeeded
事件觸發版本更改事件。此事件允許您執行數據庫架構更改或數據遷移。
這裏需要注意的一點是,刪除以前的對象存儲以添加新選項,創建新存儲時也會刪除舊存儲中的所有其他數據。在升級數據庫之前,請注意讀出舊內容並將其保存在其他位置。
8 使用索引數據庫的缺點
由於IndexedDB
依賴於客戶端的 Web
瀏覽器,因此它通常更適合個人用戶或小規模的應用程序。儘管它可以處理大量數據,但在大型應用程序或多人使用的應用程序中使用 IndexedDB
時,需要牢記某些注意事項。
可伸縮性限制
IndexedDB
在Web
瀏覽器中運行,這意味着它僅限於客戶端環境的功能和資源。對於需要處理大量併發用戶或極高吞吐量的方案,它可能無法很好地縮放。
數據大小限制
不同的Web
瀏覽器對IndexedDB
中可以存儲的最大數據量施加了限制。這些限制因瀏覽器而異,範圍從幾兆字節到幾百兆字節不等。
瞭解這些限制並相應地設計應用程序非常重要。數據存儲用完後,您將無法在數據庫中存儲新數據,因爲會觸發 QuotaExceededError
錯誤。
同步挑戰
IndexedDB
不提供內置機制來處理客戶端之間的數據同步或處理分佈式環境中的衝突。您需要實現自定義同步邏輯來處理這些方案。在應用程序的不同實例之間維護數據一致性和同步變得複雜。
因此,對於較大規模的應用程序或多人使用的應用程序,使用服務器端數據庫或基於雲的存儲解決方案更有效。
9 寫在最後
在本文中,我們瞭解了 IndexedDB
,一個 Web
上的數據庫,以及如何使用 JavaScript
與它交互以存儲 Web
應用程序數據。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/xTcolNZPfnZ3qAFaOV6Yrg