IndexedDB 与 LocalStorage 和 SessionStorage 的比较

在构建现代 Web 应用程序时,选择合适的客户端存储 API 会显著影响应用的性能和用户体验。虽然 LocalStorage 和 SessionStorage 适用于简单数据,但 IndexedDB 提供的功能使其成为离线 Web 应用和复杂数据管理的必备选择。让我们来看看这些 JavaScript 浏览器存储选项的比较,以及何时使用每一种。
核心要点
- LocalStorage 和 SessionStorage 是同步 API,仅限于存储 5-10MB 的字符串数据
- IndexedDB 提供异步、非阻塞操作,存储空间几乎无限
- IndexedDB 支持复杂数据类型、事务和索引,可实现高效查询
- 根据数据复杂度选择存储方式:简单字符串使用 LocalStorage,复杂对象需要 IndexedDB
理解三种客户端存储 API
LocalStorage:简单且持久
LocalStorage 以字符串形式存储键值对,数据会持久保存直到被明确清除。每个源的典型容量为 5-10MB,非常适合存储用户偏好设置、主题设置或小型配置数据。
localStorage.setItem('userTheme', 'dark');
const theme = localStorage.getItem('userTheme'); // Returns 'dark'
LocalStorage 的同步特性意味着每个操作都会阻塞主线程。在普通设备上,读取或写入仅 1MB 的数据就可能导致 UI 冻结 100-200 毫秒。
SessionStorage:临时标签页存储
SessionStorage 的工作方式与 LocalStorage 相同,但有一个关键区别:数据在标签页关闭时过期。它保持相同的 5-10MB 限制和同步 API,适合临时表单数据或单会话状态管理。
sessionStorage.setItem('formDraft', JSON.stringify(formData));
数据在每个标签页中是隔离的——在新标签页中打开相同页面会创建一个单独的 SessionStorage 实例。
IndexedDB 与 LocalStorage 和 SessionStorage:关键差异
存储容量和数据类型
LocalStorage 和 SessionStorage 将您限制在字符串和 5-10MB 的空间内,而 IndexedDB 可以处理几乎无限的存储空间(通常为可用磁盘空间的 50%)并直接存储 JavaScript 对象:
// IndexedDB stores complex objects without serialization
const userData = {
id: 1,
profile: { name: 'Alice', avatar: blobData },
settings: { theme: 'dark', notifications: true },
lastSync: new Date()
};
// Note: Map objects cannot be directly stored in IndexedDB
性能特征
最关键的区别在于性能。LocalStorage 和 SessionStorage 使用阻塞 JavaScript 执行的同步操作:
- LocalStorage/SessionStorage:同步,阻塞主线程
- IndexedDB:异步,非阻塞操作
对于较大的数据集,LocalStorage 由于其同步特性可能会明显阻塞 UI,而 IndexedDB 操作异步运行,保持 UI 响应流畅。
数据完整性和事务
IndexedDB 提供事务操作以确保数据一致性。如果事务的任何部分失败,所有更改都会自动回滚——这对于维护数据完整性的离线 Web 应用至关重要。
Discover how at OpenReplay.com.
IndexedDB 优于 LocalStorage 的场景
离线优先应用
考虑一个离线工作的笔记应用。使用 IndexedDB,您可以存储数千个带附件的文档,使用索引高效搜索它们,并在重新连接时同步更改——这是 LocalStorage 的限制无法实现的。
大数据集管理
电商网站可以在 IndexedDB 中缓存整个产品目录。像 Linear 这样的应用使用这种方法在本地存储项目数据,在发起服务器请求之前检查缓存有效性,显著减少加载时间。
复杂数据结构
IndexedDB 原生处理 Blob、File 和类型化数组。照片编辑应用可以直接存储图像,无需 base64 编码(在 LocalStorage 中会使大小增加 33%)。
实际实现比较
以下是存储用户数据的实际示例:
// LocalStorage - requires serialization, blocks UI
const saveToLocalStorage = (data) => {
localStorage.setItem('userData', JSON.stringify(data)); // Blocks thread
};
// IndexedDB - handles objects, non-blocking (using idb library)
const saveToIndexedDB = async (data) => {
const db = await openDB('MyApp', 1, {
upgrade(db) {
db.createObjectStore('users', { keyPath: 'id' });
}
});
const tx = db.transaction('users', 'readwrite');
await tx.objectStore('users').put(data); // Non-blocking
};
浏览器兼容性和限制
截至 2025 年,这三种 API 都享有通用的浏览器支持。但是,在隐私浏览模式下行为有所不同:
- Safari:与正常浏览相比,在隐私模式下强制执行较低的配额
- Firefox:在隐私会话结束时清除所有存储
- Chrome:在无痕模式下保持标准配额
存储清除策略也有所不同。当磁盘空间不足时,浏览器可能会清除存储,而标记为”持久”的 IndexedDB 数据会受到保护,免于自动删除。
做出正确选择
选择 LocalStorage 用于:
- 1MB 以下的用户偏好设置
- 简单字符串数据
- 快速原型开发
选择 SessionStorage 用于:
- 表单草稿
- 临时 UI 状态
- 单标签页工作流
选择 IndexedDB 用于:
- 离线功能
- 超过 5MB 的数据
- 复杂对象和文件
- 搜索和过滤需求
- 事务完整性需求
结论
虽然 LocalStorage 和 SessionStorage 对于简单的存储需求仍然很有价值,但 IndexedDB 对于构建高性能、支持离线的 Web 应用程序至关重要。其异步特性、无限容量和事务支持使其成为存储大型数据集或复杂数据结构的唯一可行选择。对于超越基本键值对的现代 JavaScript 浏览器存储需求,IndexedDB 是复杂或大规模客户端存储的推荐选择。
常见问题
不能,IndexedDB 无法直接存储 Map 和 Set 对象。您需要在存储前将它们转换为常规对象或数组。对于 Set 使用 Array.from(),对于 Map 使用 Object.fromEntries(),然后在检索数据时重新构建它们。
清除浏览器缓存通常不会影响 IndexedDB 数据。用户必须专门清除网站数据或 Cookie 才能删除 IndexedDB 内容。但是,在存储压力下,浏览器可能会清除 IndexedDB 数据,除非使用 Storage API 将其标记为持久。
对于 100KB 以下的微小数据,LocalStorage 由于其同步特性,在简单读取时可能更快。但是,IndexedDB 的非阻塞操作可以防止 UI 冻结,即使在生产应用中处理小数据集时,也能提供更好的用户体验。
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.