JavaScript - IndexedDB



什么是 IndexedDB?

IndexedDB(或索引数据库)表示低级 JavaScript API。它的功能涉及存储和检索大量结构化数据 - 这包括文件和 blob。凭借其使用客户端数据库的能力:它使 Web 应用程序能够在用户设备上本地存储、查询和修改数据。事实证明,在构建面对大量数据量的 Web 应用程序时,此功能特别有利;在没有 Internet 连接的情况下运行,离线工作,并通过本地数据缓存提供响应式用户体验。

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

删除操作

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


 const request = objectStore.delete(key);

实现示例

上述 CRUD 操作的所有重要方法都在这段代码中实现。它将数据库数据以表格的形式呈现,每条记录都附有删除和更新按钮。当您单击创建按钮时,它会在屏幕上显示用于创建表单的元素;从而允许将 name 和 email 的输入插入到数据库中。默认情况下,此表单保持隐藏状态;它仅在单击按钮时显示,随后在任务完成时消失。'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>

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