JavaScript - IndexedDB



什麼是 IndexedDB?

IndexedDB,或索引資料庫,是一個低階的 JavaScript API。其功能包括儲存和檢索大量結構化資料,包括檔案和 Blob。它能夠與客戶端資料庫互動,使 Web 應用程式能夠在使用者的裝置上本地儲存、查詢和修改資料。此功能在構建處理大量資料、離線工作以及透過本地資料快取提供響應式使用者體驗的 Web 應用程式時尤其有用。

IndexedDB 的關鍵概念和特性

  • 非同步 API − IndexedDB 使用非同步 API,依賴於事件驅動的程式設計,以防止主執行緒阻塞並增強使用者體驗。

  • 資料庫 − IndexedDB 資料庫充當物件儲存的容器,便於資料的組織、檢索和刪除。

  • 物件儲存 − 物件儲存類似於關係資料庫中的表,封裝 JavaScript 物件的集合;它支援 CRUD 操作。

  • 索引 − 物件儲存中的索引可以提高資料查詢效率,因為它們能夠根據特定欄位提高搜尋和排序效能。

  • 事務 − IndexedDB 中的事務執行所有操作,透過使多個操作作為一個單元成功或失敗來保證一致性和完整性。

為什麼要使用 IndexedDB?

Web 開發人員在尋找高效的客戶端儲存解決方案時,發現 IndexedDB 不可或缺。它的非同步特性保證了響應式的使用者體驗:它避免了主執行緒阻塞;此外,它對事務的支援透過維護資料完整性值得稱讚。IndexedDB 能夠本地管理大量結構化資料;此功能大大增強了離線功能,減少了對持續伺服器通訊的需求。憑藉其靈活的鍵結構、對最佳化查詢的索引支援以及升級模式的能力,它是構建需要本地儲存、離線支援和高效資料管理的 Web 應用程式的強大選擇。

CRUD 操作

現在讓我們看看 IndexedDB 的 CRUD 操作程式碼。

建立/插入操作

要在物件儲存中插入新記錄,可以使用 IndexedDB 中的 add() 方法。此方法接受 JavaScript 物件或值作為引數,然後將其新增到指定的物件儲存中。但是,如果已經存在具有相同鍵引數的條目,則此操作將失敗,因此它非常適合保證唯一性。

const request = objectStore.add(data);
request.onsuccess = () => {
// Handle success event
};

request.onerror = () => {
// Handle error
};

讀取 (檢索) 操作

get() 方法

使用 get() 方法:它從物件儲存中檢索單個記錄,此操作取決於您是否知道目標條目的特定鍵。

openCursor() 方法

啟動一個主動遊標來迭代物件儲存中的記錄,openCursor() 方法透過允許處理每個單獨的條目來提高效率和控制;這在遍歷物件儲存中存在的全部條目時非常有用。

const request = objectStore.openCursor();
request.onsuccess = (event) => {
   const cursor = event.target.result;
   if (cursor) {
      const data = cursor.value;
      // Process data
      cursor.continue();
   }
};

request.onerror = () => {
   // Handle error
};

更新操作

put() 方法更新現有記錄,或者在鍵不存在時新增新記錄。它的多功能性使其適合於資料操作,特別是更新和插入。

const request = objectStore.put(data);

刪除操作

要根據其鍵從物件儲存中刪除特定記錄,必須使用 delete() 方法;此方法提供了一種直接刪除條目的方法。

const request = objectStore.delete(key);

實現示例

上述所有重要的 CRUD 操作方法都在此程式碼中實現。它將資料庫資料顯示為表格,每條記錄都帶有刪除和更新按鈕。單擊建立按鈕時,它會在螢幕上顯示一個用於表單建立的元素;從而允許輸入姓名和電子郵件以插入到資料庫中。預設情況下,此表單隱藏;它只在單擊按鈕後出現,並在其任務完成後消失。'prompt()' 方法填充了詳細資訊更新表單,此功能為使用者提供了便利,因為警報也出現在同一位置。此外:相關的警報用於向用戶發出成功事件或錯誤的訊號。

<!DOCTYPE html>
<html>
<head>
   <style>
      body {
         font-family: Arial, sans-serif;
         margin: 20px;
      }
      h2 {
         color: #333;
      }

      button {
         padding: 8px;
         margin: 5px;
      }

      #createForm, #updateForm {
         display: none;
         border: 1px solid #ddd;
         padding: 10px;
         margin-bottom: 10px;
      }

      table {
         border-collapse: collapse;
         width: 100%;
         margin-top: 20px;
         width: auto;
      }

      th, td {
         border: 1px solid #dddddd;
         text-align: left;
         padding: 8px;
      }

      th {
         background-color: #f2f2f2;
      }
   </style>
</head>
<body>
   <h2>IndexedDB CRUD Operations</h2>
   <button onclick="showCreateForm()">Create Data</button>
   <div id="createForm" style="display: none;">
      // hidden by default, displayed on create button click
      <h3>Create Data</h3>
      <label for="name">Name:</label>
      <input type="text" id="name" required><br><br>
      <label for="email">Email:</label>
      <input type="email" id="email" required><br>
      <button onclick="createData()">Save</button>
      <button onclick="cancelCreate()">Cancel</button>
   </div>
   <table id="data-table">
      <thead>
         <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Email</th>
            <th>Actions</th>
         </tr>
      </thead>
      <tbody></tbody>
   </table>
   <script>
      const dbName = "myDatabase";
      let db;
	   // Open/create indexedDB named myDatabase with version 11
      const request = window.indexedDB.open(dbName, 11);
      request.onerror = (event) => {
         alert("Database error: " + event.target.errorCode);
      };

      request.onsuccess = (event) => {
         db = event.target.result;
         showData();
      };
      request.onupgradeneeded = (event) => {
         db = event.target.result;
         const objectStore = db.createObjectStore("myObjectStore", { keyPath: "id", autoIncrement: true });
         objectStore.createIndex("name", "name", { unique: false });
         objectStore.createIndex("email", "email", { unique: true });
      };
      function showData() {
         //populates the table from the db
         const transaction = db.transaction(["myObjectStore"], "readonly");
         const objectStore = transaction.objectStore("myObjectStore");
         const tableBody = document.querySelector("#data-table tbody");
         tableBody.innerHTML = "";
         const request = objectStore.openCursor();
         request.onsuccess = (event) => {
            const cursor = event.target.result;
            if (cursor) {
               const row = tableBody.insertRow();
               row.insertCell(0).textContent = cursor.value.id;
               row.insertCell(1).textContent = cursor.value.name;
               row.insertCell(2).textContent = cursor.value.email;
               const actionsCell = row.insertCell(3);
               //update & delete is performed on the basis of id, hence id is passed as parameter to functions when corresponding button is clicked
               actionsCell.innerHTML = `
               <button onclick="showUpdateForm(${cursor.value.id})">Update</button>
               <button onclick="deleteData(${cursor.value.id})">Delete</button>
                    `;
               cursor.continue();
            }
         };
      }

      function createData() {
         const transaction = db.transaction(["myObjectStore"], "readwrite");
         const objectStore = transaction.objectStore("myObjectStore");
         const name = document.getElementById("name").value;
         const email = document.getElementById("email").value;

         const newData = {
            name: name,
            email: email
         };

         const request = objectStore.add(newData);

         request.onsuccess = () => {
            showData();
            cancelCreate();
            alert("Data added successfully")
         };

         request.onerror = () => {
            alert("Error creating data.");
         };
      }

      function showCreateForm() {
         document.getElementById("createForm").style.display = "block";
      }

      function cancelCreate() {
      //if the user decides to not insert the record.
      document.getElementById("createForm").style.display = "none";
         document.getElementById("name").value = "";
         document.getElementById("email").value = "";
      }

      function showUpdateForm(id) {
         const transaction = db.transaction(["myObjectStore"], "readwrite");
         const objectStore = transaction.objectStore("myObjectStore");

         const request = objectStore.get(id);

         request.onsuccess = (event) => {
            const data = event.target.result;
 
            if (data) {
               const name = prompt("Update Name:", data.name);
               const email = prompt("Update Email:", data.email);

               if (name !== null && email !== null) {
                  data.name = name;
                  data.email = email;

                  const updateRequest = objectStore.put(data);

                  updateRequest.onsuccess = () => {
                     showData();
                     alert("Updated data for "+data.name)
                  };

                  updateRequest.onerror = () => {
                     alert("Error updating data.");
                  };
               }
            }
         };
      }

      function deleteData(id) {
         const transaction = db.transaction(["myObjectStore"], "readwrite");
         const objectStore = transaction.objectStore("myObjectStore");
 
         const request = objectStore.delete(id);
 
         request.onsuccess = () => {
            showData();
            alert("Deleted data for id "+id)
         };

         request.onerror = () => {
            alert("Error deleting data.");
         };
      }
     
   </script>
</body>
</html>

嘗試執行上述程式。在輸出中,您將獲得一個建立、更新和刪除資料的介面。新建立或更新的資料將在操作完成後立即以表格形式出現。

廣告