Javascript 简明教程

JavaScript - IndexedDB

What is IndexedDB?

IndexedDB 或 Indexed Database 表示一个低级别的 JavaScript API。它的功能涉及存储和检索大量结构化数据 - 这包括文件和 blob。利用它使用客户端数据库的能力:它使 web 应用程序能够在用户设备上本地存储、查询和修改数据。该功能在构建面对大量数据的 web 应用程序时尤其有利;在没有互联网连接时仍然能离线操作,并且通过本地数据缓存提供响应的用户体验。

IndexedDB 的关键概念和特性:

  1. Asynchronous API − 依赖事件驱动的编程,IndexedDB 使用异步 API 来防止主线程阻塞和增强用户体验。

  2. Database − IndexedDB 数据库用作存储对象容器,帮助组织、检索和删除数据。

  3. Object Store − 对象存储类似于关系数据库中的表,封装了 JavaScript 对象的集合;它提供对 CRUD 操作的支持。

  4. Index − 对象存储中的索引可以提高数据查询的效率,因为它们能够根据特定字段改进搜索和排序的性能。

  5. Transactions − IndexedDB中的事务执行所有操作,通过使其能够将多个动作作为单元成功或失败来保证一致性和完整性。

Why use IndexedDB?

Web开发者在寻找高效的客户端存储解决方案时,发现IndexedDB必不可少。其异步性质保证了响应式用户体验:它阻止了主线程阻塞;此外,值得称赞的是,它支持通过维护数据完整性来进行事务。IndexedDB能够在本地管理大量结构化数据;这种能力显著增强了离线功能,减少了对频繁服务器通信的需求。凭借其灵活的关键结构、对优化查询的索引支持,以及升级模式的能力;它成为了构建Web应用程序的强大选择。这些应用程序通常需要本地存储、离线支持和最重要的是有效的数据管理。

CRUD Operations

现在让我们看看使用IndexedDB进行CRUD操作的代码。

Create/Insert Operation

要在对象存储中插入新记录,可以在IndexedDB中使用add()方法。此方法接受一个JavaScript对象或值作为其参数,然后将其并入指定的object store中。但是,如果已经存在具有相同关键参数的条目;此操作将失败,因此使其成为保证唯一性的理想选择。

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

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

Read (Retrieve) Opeation

利用 get()方法:它从对象存储区中检索单个记录,此操作取决于您对目标条目特定键的了解。

通过启动一个活动光标遍历对象存储区内的记录,open Cursor()方法通过允许处理每个单独条目来提高效率和控制力;这对于遍历该对象存储区中存在的所有条目很有用。

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

Update Operation

当键不存在时,put()方法更新现有记录或添加新记录。它的通用性使其适用于数据操作,特别是更新和插入。

const request = objectStore.put(data);

Delete Operation

为了根据其键从对象存储中删除特定记录,必须使用 delete() 方法;此方法提供了一种直接的删除条目方法。

const request = objectStore.delete(key);

Implementation Example

上述 CRUD 操作的所有重要方法都在此代码中实现。它将数据库数据表示为一个表格,每条记录都附有删除和更新按钮。当您单击“create”按钮时,它在屏幕上显示用于创建表单的元素;从而允许将姓名和电子邮件输入到数据库中。默认情况下,此表单保持隐藏;只有在单击按钮后才会出现,并在其任务完成后消失。“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>

尝试运行上述程序。在输出中,您将获得一个创建、更新和删除数据的界面。新创建或更新的数据将在操作完成后以表格形式显示。