# indexedDB-demos **Repository Path**: steveouyang/indexed-db-demos ## Basic Information - **Project Name**: indexedDB-demos - **Description**: 学习前端存储利器indexedDB的使用吧! - **Primary Language**: Unknown - **License**: ISC - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2023-07-15 - **Last Updated**: 2023-07-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## @前端存储 在前端开发中,有几种常见的方式可以进行数据存储: 1. Cookie:Cookie 是一种存储在用户本地浏览器中的小型文本文件。它可以被用来存储和获取有限量的数据。Cookie 在前端通常用于存储会话信息、用户偏好设置等,但存储容量有限制,并且会在每次请求时都会发送到服务器端。 2. Local Storage:本地存储是一种支持持久化存储的 Web API。它允许在用户浏览器中存储键值对数据,这些数据会一直保存在用户的本地,不会随着请求发送到服务器。Local Storage 提供了较大的存储容量,可以存储大量数据,但只能存储字符串类型的值。 3. Session Storage:会话存储与本地存储类似,也是一种用于在用户浏览器中存储键值对数据的 Web API。不同之处在于会话存储的数据在用户会话结束后会被清除,而本地存储的数据则会持久保存。会话存储适用于临时的、会话级别的数据存储需求。 4. **IndexedDB:IndexedDB 是一个内置在浏览器中的客户端数据库,允许存储大量结构化数据。它提供了更强大的存储功能,支持事务操作和复杂的查询。IndexedDB 是一个异步的、基于事件的 API,需要一定的学习和使用成本。** 5. Web Storage API:Web Storage API 是 localStorage 和 sessionStorage 的统称,提供了对于本地存储和会话存储的访问。它们使用简单的键值对方式来存储数据,是一种比较方便的数据存储方式。 选择适当的存储方式取决于具体的需求。如果只需要存储少量数据或会话级别的数据,可以使用 Cookie、Local Storage 或 Session Storage。如果需要处理大容量的结构化数据或复杂的查询,可以考虑使用 IndexedDB。 需要注意的是,存储在客户端的数据始终是不安全的,敏感信息应该避免直接存储在前端。为了确保数据安全性,可以进行加密、验证和服务器端验证等措施。 ## @indexedDB基础使用案例 下面是一个使用 IndexedDB 的基础使用案例,包括创建数据库、创建对象存储空间、添加数据和检索数据的例子。 ```javascript // 打开或创建数据库 const request = indexedDB.open("myDatabase", 1); // 创建对象存储空间及索引 request.onupgradeneeded = function(event) { const db = event.target.result; // 创建对象存储空间 const objectStore = db.createObjectStore("customers", { keyPath: "id" }); // 创建索引(如果需要) objectStore.createIndex("name", "name", { unique: false }); objectStore.createIndex("email", "email", { unique: true }); // 数据库结构创建完毕后会触发 success 事件 request.onsuccess = function(event) { console.log("数据库已创建"); }; }; // 数据库成功打开后的回调函数 request.onsuccess = function(event) { const db = event.target.result; // 添加数据 const transaction = db.transaction(["customers"], "readwrite"); const objectStore = transaction.objectStore("customers"); const customer = { id: 1, name: "John Doe", email: "john@example.com" }; const request = objectStore.add(customer); request.onsuccess = function(event) { console.log("数据已添加"); }; // 检索数据 const getCustomerRequest = objectStore.get(1); getCustomerRequest.onsuccess = function(event) { const result = event.target.result; console.log(result); }; }; // 错误处理 request.onerror = function(event) { console.log("数据库打开失败"); }; ``` 上述示例中,首先使用 `indexedDB.open` 方法打开或创建一个名为 "myDatabase" 的数据库。在 `onupgradeneeded` 回调函数中,我们创建了一个名为 "customers" 的对象存储空间,并在其中创建了名为 "name" 和 "email" 的索引。 在 `onsuccess` 回调函数中,我们使用创建的数据库对象,添加了一条数据,并使用 `get` 方法检索出相应的数据。 这只是一个简单的使用 IndexedDB 的例子,实际使用中可以根据需求进行增删改查的操作,处理错误和事务等。 ## @访问以前存储的数据 如果你之前使用过 IndexedDB 存储了数据,并且想要访问之前存储的数据,你可以使用以下步骤来检索数据: 1. 打开或创建数据库: ```javascript const request = indexedDB.open("myDatabase", 1); ``` 2. 数据库成功打开后的回调函数中,打开事务并获取对象存储空间: ```javascript request.onsuccess = function(event) { const db = event.target.result; const transaction = db.transaction(["customers"], "readonly"); const objectStore = transaction.objectStore("customers"); }; ``` 3. 使用 `getAll` 方法获取存储空间中的所有数据: ```javascript const getAllRequest = objectStore.getAll(); getAllRequest.onsuccess = function(event) { const result = event.target.result; console.log(result); }; ``` 在上述代码中,我们打开或创建名为 "myDatabase" 的数据库,并获取 "customers" 对象存储空间的只读事务。接着,我们使用 `getAll` 方法获取存储空间中的所有数据,并在 `onsuccess` 回调函数中打印出结果。 通过以上步骤,你可以访问之前存储在 IndexedDB 中的数据。 需要注意的是,如果之前的存储空间或数据库结构有所变化,你可能需要进行相应的修改,以适应新的结构。 整段复制吧 ↓↓ ```javascript // 打开或创建数据库 const request = indexedDB.open("myDatabase", 1); // 数据库成功打开后的回调函数 request.onsuccess = function(event) { const db = event.target.result; // 打开事务并获取对象存储空间 const transaction = db.transaction(["customers"], "readonly"); const objectStore = transaction.objectStore("customers"); // 使用 getAll 方法获取存储空间中的所有数据 const getAllRequest = objectStore.getAll(); getAllRequest.onsuccess = function(event) { const result = event.target.result; console.log(result); }; }; // 创建对象存储空间及索引 request.onupgradeneeded = function(event) { const db = event.target.result; // 创建对象存储空间 const objectStore = db.createObjectStore("customers", { keyPath: "id" }); // 创建索引(如果需要) objectStore.createIndex("name", "name", { unique: false }); objectStore.createIndex("email", "email", { unique: true }); }; // 错误处理 request.onerror = function(event) { console.log("数据库打开失败"); }; ``` 在上述代码中,首先使用 `indexedDB.open` 方法打开或创建一个名为 "myDatabase" 的数据库。在 `onupgradeneeded` 回调函数中,我们创建了一个名为 "customers" 的对象存储空间,并在其中创建了名为 "name" 和 "email" 的索引。 在 `onsuccess` 回调函数中,我们使用成功打开的数据库对象,打开只读事务,并获取了 "customers" 对象存储空间。接着,我们使用 `getAll` 方法获取存储空间中的所有数据,并在 `onsuccess` 回调函数中打印出结果。 通过以上步骤,你可以方便地复制代码并访问之前存储在 IndexedDB 中的数据。 ## @indexedDB的核心常用API 下面是 IndexedDB 的核心常用 API 的一些例子: 1. indexedDB.open(databaseName, version):打开或创建一个指定名称和版本的数据库。 ```javascript const request = indexedDB.open("myDatabase", 1); ``` 2. request.onupgradeneeded:创建或升级数据库结构的事件回调。 ```javascript request.onupgradeneeded = function(event) { const db = event.target.result; // 创建对象存储空间,设置索引等 }; ``` 3. request.onsuccess:数据库成功打开后的事件回调。 ```javascript request.onsuccess = function(event) { const db = event.target.result; // 可以进行数据操作 }; ``` 4. request.onerror:错误处理的事件回调。 ```javascript request.onerror = function(event) { console.log("数据库打开失败"); }; ``` 5. db.createObjectStore(storeName, options):在数据库中创建一个对象存储空间(表)。 ```javascript const objectStore = db.createObjectStore("customers", { keyPath: "id" }); ``` 6. objectStore.add(data):向对象存储空间中添加数据。 ```javascript const request = objectStore.add({ id: 1, name: "John Doe", email: "john@example.com" }); ``` 7. objectStore.get(key):根据主键从对象存储空间中检索数据。 ```javascript const getRequest = objectStore.get(1); getRequest.onsuccess = function(event) { const result = event.target.result; console.log(result); }; ``` 8. objectStore.getAll():从对象存储空间中获取所有数据。 ```javascript const getAllRequest = objectStore.getAll(); getAllRequest.onsuccess = function(event) { const result = event.target.result; console.log(result); }; ``` 9. objectStore.delete(key):根据主键从对象存储空间中删除数据。 ```javascript const deleteRequest = objectStore.delete(1); deleteRequest.onsuccess = function(event) { console.log("数据已删除"); }; ``` 这些是 IndexedDB 的核心常用 API。通过这些 API,你可以创建、升级、打开和关闭数据库,以及进行数据的增删改查等操作。 ## @退出时需要关闭数据库吗 在页面退出时,关闭 IndexedDB 数据库是一个良好的实践,但并不是必需的步骤。IndexedDB API 会帮助处理数据库的开启和关闭,以确保数据库在不再被需要时能够自动关闭。 通常情况下,当页面被关闭或刷新时,IndexedDB API 会自动关闭数据库连接。但是,这种自动关闭不是立即执行的,而是在所有的事务和数据库操作都完成后进行。 如果你确定不再需要数据库连接时,你可以手动关闭数据库以确保及时释放资源。以下是一个示例代码,展示了如何手动关闭数据库连接: ```javascript // 关闭数据库连接 db.close(); // 或者通过请求对象关闭 request.result.close(); ``` 需要注意的是,在手动关闭数据库之后,就无法再进行任何数据操作。因此,请确保在所有的读写操作完成后再手动关闭数据库连接。 虽然 IndexedDB API 可以自动关闭数据库,但在页面退出前手动关闭数据库连接是一个良好的实践,可以帮助释放资源并确保代码的健壮性。 ## @进阶思路 看样子已经可以把indexedDB用起来了,继续进阶怎么玩呢? 下面是一些进阶的方式,让你更好地利用 IndexedDB: 1. **事务管理:IndexedDB 使用事务来执行读取和写入操作,确保数据的一致性和完整性。了解不同类型的事务(只读事务和读写事务),正确使用事务可以提高你的代码性能和效率。** 2. **索引:IndexedDB 支持创建索引以提高查询速度。你可以使用 `createIndex` 方法在对象存储空间中创建索引,并在查询时使用索引加快检索速度。** 3. 游标:游标(Cursor)是 IndexedDB 的一种功能,它允许你按照特定的顺序遍历存储空间中的数据。使用游标可以实现更复杂的查询,如范围查询、条件查询等。 4. **错误处理:了解 IndexedDB 中的常见错误类型和错误码,并正确处理错误。这样可以使你的代码更健壮、更可靠。** 5. **数据库版本升级:如果你需要在数据结构发生变化时进行数据库的升级操作,你可以使用 `onupgradeneeded` 事件来处理。在该事件中,可以创建新的对象存储空间、修改已有的对象存储空间以及迁移数据。** 6. 跨浏览器兼容性:尽管大多数现代浏览器都支持 IndexedDB,但仍然有一些浏览器可能存在兼容性问题。学习如何检测 IndexedDB 的兼容性,并在必要时使用其他存储机制作为备选方案。 除了上述内容,还有许多其他的进阶技巧和最佳实践可以提升你对 IndexedDB 的使用。如果你对某个特定的方面感兴趣,我可以为你提供更详细的信息和示例代码。 继续学习并尝试使用不同的功能和技巧,你会逐渐成为一个熟练的 IndexedDB 开发者! ## @事务案例 来一个综合一点的事务的例子吧! 当涉及到一系列的读取和写入操作时,使用事务可以确保数据的一致性和完整性。下面是一个综合性的事务示例,展示了如何通过事务来执行一系列读写操作: ```javascript // 打开数据库连接 const request = indexedDB.open("myDatabase", 1); let db; request.onerror = function(event) { console.log("数据库打开失败"); }; request.onsuccess = function(event) { db = event.target.result; // 执行事务 doTransaction(); }; function doTransaction() { // 开启读写事务 const transaction = db.transaction(["customers"], "readwrite"); const objectStore = transaction.objectStore("customers"); // 添加数据 const addRequest = objectStore.add({ id: 1, name: "John Doe", email: "john@example.com" }); addRequest.onerror = function(event) { console.log("数据添加失败"); }; addRequest.onsuccess = function(event) { console.log("数据添加成功"); }; // 查询数据 const getRequest = objectStore.get(1); getRequest.onerror = function(event) { console.log("数据查询失败"); }; getRequest.onsuccess = function(event) { const result = event.target.result; console.log("查询结果:", result); }; // 更新数据 const updateRequest = objectStore.put({ id: 1, name: "John Smith", email: "john@example.com" }); updateRequest.onerror = function(event) { console.log("数据更新失败"); }; updateRequest.onsuccess = function(event) { console.log("数据更新成功"); }; // 删除数据 const deleteRequest = objectStore.delete(1); deleteRequest.onerror = function(event) { console.log("数据删除失败"); }; deleteRequest.onsuccess = function(event) { console.log("数据删除成功"); }; // 事务完成 transaction.oncomplete = function(event) { console.log("事务完成"); // 关闭数据库连接(这一步也可以省略) db.close(); }; transaction.onerror = function(event) { console.log("事务错误"); }; } ``` 在上述代码中,我们首先打开数据库连接,并在成功打开后执行 `doTransaction` 函数。在 `doTransaction` 函数中,我们创建一个读写事务,并使用事务内部的对象存储空间执行一系列操作: - 添加数据:使用 `add` 方法向对象存储空间中添加数据。 - 查询数据:使用 `get` 方法查询指定主键的数据。 - 更新数据:使用 `put` 方法更新指定主键的数据。 - 删除数据:使用 `delete` 方法删除指定主键的数据。 在每个操作后,我们处理成功或失败的回调函数。最后,在事务的 `oncomplete` 事件处理函数中,我们进行清理操作,并可以选择手动关闭数据库连接。 请注意,在事务内部的多个操作会按照事务顺序依次执行,只有当所有操作成功完成时,事务才会成功。如果有任何操作失败,事务将回滚,并触发事务的 `onerror` 事件处理函数。 这个综合的事务示例可以帮助你理解如何使用事务来执行一系列的数据操作。你可以根据自己的需求修改和扩展代码。 ## @事务错误处理 要查看事务错误的具体信息,你可以使用事务的 `error` 事件来捕获错误,并进一步检查错误对象的属性以获取更多信息。以下是一个示例代码,展示了如何查看事务错误的具体信息: ```typescript function doTransaction() { const transaction = db.transaction(["customers"], "readwrite"); const objectStore = transaction.objectStore("customers"); // ... transaction.oncomplete = function(event) { console.log("事务完成"); // 关闭数据库连接 db.close(); }; transaction.onerror = function(event) { const error = event.target.error; // 获取错误对象 console.log("事务错误:", error); console.log("错误码:", error.code); console.log("错误名称:", error.name); console.log("错误信息:", error.message); // 可能还有其他的错误属性可供查看 // 如果需要进一步处理错误,可以抛出异常或执行其他操作 // throw new Error("事务发生错误"); }; } ``` 在上述代码中,当事务发生错误时,`transaction.onerror` 事件处理函数会被触发。你可以通过 `event.target.error` 获取错误对象,并查看其属性,例如 `code`、`name` 和 `message`。根据需要,你可以执行其他操作,如抛出异常或执行错误处理逻辑。 注意:在事务错误的情况下,事务会被中止,后续的操作将不会执行。因此,如果遇到错误,你可能需要根据具体情况进行处理,例如回滚操作或其他错误处理策略。 ## @indexedDB的数据类型 当使用 TypeScript 开发 IndexedDB 应用时,可以使用以下类型定义来对数据库、对象存储空间和索引进行类型检查和推断: 1. 数据库类型定义: ```typescript type Database = IDBDatabase; ``` 2. 对象存储空间类型定义: ```typescript type ObjectStore = IDBObjectStore; ``` 3. 索引类型定义: ```typescript type Index = IDBIndex; ``` 4. 事务类型定义: ```typescript type Transaction = IDBTransaction; ``` 5. 游标类型定义: ```typescript type CursorWithValue = IDBCursorWithValue; ``` 请注意,这里使用的是内置的 IndexedDB 类型定义,因此不需要额外安装类型声明库。 使用这些类型定义,你可以在 TypeScript 中对数据库、对象存储空间、索引、事务和游标等进行类型注解,从而提高代码的可读性和可维护性。例如: ```typescript const request: IDBOpenDBRequest = indexedDB.open("myDatabase", 1); let db: Database; request.onerror = function(event: Event) { console.log("数据库打开失败"); }; request.onsuccess = function(event: Event) { db = request.result; // 执行事务 doTransaction(); }; function doTransaction() { const transaction: Transaction = db.transaction(["customers"], "readwrite"); const objectStore: ObjectStore = transaction.objectStore("customers"); // ... const getRequest: IDBRequest = objectStore.get(1); getRequest.onerror = function(event: Event) { console.log("数据查询失败"); }; getRequest.onsuccess = function(event: Event) { const result: unknown = getRequest.result; console.log("查询结果:", result); }; // ... transaction.oncomplete = function(event: Event) { console.log("事务完成"); // 关闭数据库连接 db.close(); }; transaction.onerror = function(event: Event) { console.log("事务错误"); }; } ``` 以上是一些基本的类型定义示例,你可以根据自己的需求进行调整和扩展。