Skip to content

IndexedDB - 错误处理

在现代异步 JavaScript 中,处理错误的最佳方式是使用 Promise 和 async/await。原生的 IndexedDB API 是基于事件的,这可能会导致代码冗长。我们可以将 IndexedDB 的请求封装在 Promise 中,以简化代码并使用标准的 try...catch 块进行健壮的错误处理。

IndexedDB 中的错误可能因多种原因而发生:

  • 约束违规(例如,尝试添加一个键 (key) 已存在的对象)。
  • 超出存储配额。
  • 尝试对不再活跃的事务 (transaction) 执行操作。
  • 查询不存在的对象仓库 (object store) 或索引 (index)。

未处理的错误通常会中止整个事务,回滚其中所做的任何更改。正确的错误处理使您能够捕获这些问题,通知用户,并防止应用程序崩溃。

让我们首先了解如何将一个标准的基于事件的请求转换为 Promise。这种模式是现代 IndexedDB 工作方式的基础。

// 一个将 IDBRequest Promise 化的辅助函数
function promisifyRequest(request) {
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}

这是一个完整的现代示例,演示了如何捕获 ConstraintError。当尝试添加一个在对象仓库 (object store) 中 keyPath 已存在的对象时,就会发生此错误。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>IndexedDB Modern Error Handling</title>
</head>
<body>
<h1>Check the console for output.</h1>
<script>
const DB_NAME = "ErrorHandlingDB";
const DB_VERSION = 1;
const STORE_NAME = "products";
async function setupDatabase() {
const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains(STORE_NAME)) {
db.createObjectStore(STORE_NAME, { keyPath: "id" });
console.log(`Object store '${STORE_NAME}' created.`);
}
};
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
async function addProduct(db, product) {
const transaction = db.transaction(STORE_NAME, "readwrite");
const store = transaction.objectStore(STORE_NAME);
const request = store.add(product);
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error); // 该错误将被我们的 try...catch 块捕获
transaction.oncomplete = () => console.log(`Transaction completed for adding product ${product.id}.`);
});
}
async function main() {
try {
const db = await setupDatabase();
console.log("Database opened successfully.");
const product1 = { id: "p1", name: "Laptop", price: 1200 };
await addProduct(db, product1);
console.log(`Successfully added product with ID: ${product1.id}`);
// 现在,我们尝试再次添加相同的产品以触发错误
console.log("Attempting to add a duplicate product...");
const product2_duplicate = { id: "p1", name: "Gaming Laptop", price: 1500 };
await addProduct(db, product2_duplicate);
} catch (error) {
console.error("An error occurred:", error.name);
if (error.name === 'ConstraintError') {
console.log("这是一个 ConstraintError。这很可能意味着产品 ID 已经存在。");
} else {
console.log("发生了一个意外错误。");
}
}
}
main();
</script>
</body>
</html>
  • ConstraintError(约束错误): 如上所示,当唯一性约束被违反时(例如,主键重复)会发生此错误。
  • TransactionInactiveError(事务不活跃错误): 如果您在事务完成后尝试执行操作,就会发生此错误。请确保所有请求都在创建事务后立即发出。
  • NotFoundError(未找到错误): 如果您尝试访问不存在的对象仓库 (object store) 或索引 (index),就会发生此错误。这通常指向版本问题或名称拼写错误。
  • DataError(数据错误): 当您尝试保存的数据无效时发生,例如,如果尝试保存一个无法克隆的对象。
  • 调试提示: 使用浏览器的开发者工具(应用程序 > 存储 > IndexedDB)来检查数据库、查看其内容并在需要时清除它。