IndexedDB 的完整使用指南

原文作者:Chibuike Nwachukwu

原文地址:https://blog.logrocket.com/using-indexeddb-complete-guide/

翻譯:一川

1 寫在前面

數據存儲是大多數 Web 應用程序的重要組成部分,從跟蹤用戶數據到應用程序數據。隨着更快、更強大的Web應用程序的快速開發,需要高效的客戶端存儲來幫助開發。

多年來,Web 上的客戶端存儲已經發生了很大的變化,從用於存儲用戶數據的 cookieWebSQL(目前已棄用)的出現,它允許開發人員將數據存儲在瀏覽器中的 SQL 數據庫中,進而允許熟悉SQL的用戶輕鬆構建健壯的應用程序。

IndexedDBWebSQL的替代品,提供比以前的同類產品更多的存儲容量。在本教程中,我們將探討如何使用和設置 IndexedDB 進行 Web 應用程序數據存儲,以及如何使用可用的 API 操作其數據。

2 什麼是 IndexedDB

IndexedDB 是用於客戶端存儲的低級 API。它是一個成熟的、持久的 NoSQL 存儲系統,可在瀏覽器中使用,允許存儲不同類型的數據,例如:

IndexedDB 可用於各種場景,例如緩存、PWA、遊戲等,並且還支持事務。它的開發是爲了有效地滿足 Web 應用程序的多種需求。

3 設置我們的項目

我們不會做任何花哨的設置,因爲IndexedDB在網絡上本地運行。首先,創建一個新目錄來容納項目:

mkdir indexed-db && cd indexed-db

現在,我們將創建一個文件來查看我們的應用程序,創建一個index.js腳本 index.html 文件來存儲我們的應用程序邏輯:

touch index.html index.js styles.css

4 將數據保存到索引數據庫

若要了解使用此數據庫的好處並瞭解如何與 API 交互,我們將創建一個基本的待辦事項應用程序。我們啓用一個添加功能以查看如何將數據保存到數據庫,另一個功能用於查看所有待辦事項,以及一個刪除功能以查看 APIGETDELETE 函數。

打開在上一節中創建的,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 時,需要牢記某些注意事項。

可伸縮性限制

IndexedDBWeb瀏覽器中運行,這意味着它僅限於客戶端環境的功能和資源。對於需要處理大量併發用戶或極高吞吐量的方案,它可能無法很好地縮放。

數據大小限制

不同的Web瀏覽器對IndexedDB中可以存儲的最大數據量施加了限制。這些限制因瀏覽器而異,範圍從幾兆字節到幾百兆字節不等。

瞭解這些限制並相應地設計應用程序非常重要。數據存儲用完後,您將無法在數據庫中存儲新數據,因爲會觸發 QuotaExceededError 錯誤。

同步挑戰

IndexedDB 不提供內置機制來處理客戶端之間的數據同步或處理分佈式環境中的衝突。您需要實現自定義同步邏輯來處理這些方案。在應用程序的不同實例之間維護數據一致性和同步變得複雜。

因此,對於較大規模的應用程序或多人使用的應用程序,使用服務器端數據庫或基於雲的存儲解決方案更有效。

9 寫在最後

在本文中,我們瞭解了 IndexedDB,一個 Web 上的數據庫,以及如何使用 JavaScript 與它交互以存儲 Web 應用程序數據。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/xTcolNZPfnZ3qAFaOV6Yrg