Appearance
本地存储
元信息
- 目标:掌握 cookie 之外的纯客户端持久化谱系——KV 阵营(localStorage/sessionStorage)与数据库阵营(IndexedDB/OPFS)的能力边界,能按数据形态选对存储方案
- 关键概念:localStorage、sessionStorage、IndexedDB、OPFS、对象仓库、事务
- 关联阶段:cp3
- 常见误区:以为 localStorage 什么都能存(仅字符串、约 5MB、同步阻塞主线程);以为 IndexedDB 只是放大版 localStorage(它是对象库+索引+事务的异步数据库);以为本地存储的数据会随请求发给服务器(不随 HTTP 走,cookie 才会)
问题的提出
- cookies 不适合存储大容量数据,因其基于http协议,每次连接均会在客户端和服务器之间被传输,网络压力很大
- cookies 没有提供结构化的存储接口,完全基于字符串,操作不便
于是浏览器陆续内置了多种纯客户端的本地存储机制。它们分两大阵营:
- KV(键值对)阵营:localStorage / sessionStorage —— 简单字符串存取,像一个大号字典
- 数据库阵营:IndexedDB(对象/索引)、OPFS(文件)—— 结构化、可查询、可事务
全家福对照
| cookie | localStorage | sessionStorage | IndexedDB | OPFS | |
|---|---|---|---|---|---|
| 出现年代 | 1994 | 2009 | 2009 | 2010 | 2021 |
| 存储模型 | 字符串键值 | 字符串键值 | 字符串键值 | 对象库+索引 | 私有文件系统 |
| 容量 | ~4KB | ~5-10MB | ~5MB | 数百MB~GB级 | GB级 |
| 随HTTP发送 | ✅ 每次请求 | ❌ | ❌ | ❌ | ❌ |
| 生命周期 | 可设过期 | 永久 | 标签页关闭即清 | 永久 | 永久 |
| API 风格 | 同步 | 同步 | 同步 | 异步(事件) | 异步(Promise) |
| 事务/索引 | ❌ | ❌ | ❌ | ✅ | ❌ |
| 典型用途 | 身份/会话凭证 | 偏好设置、草稿 | 一次性表单状态 | 离线应用的主数据库 | 大文件、音视频素材 |
选型一句话:几 KB 的偏好设置用 localStorage;结构化业务数据、要查询要离线,用 IndexedDB;大文件用 OPFS;需要随请求走的服务端状态,才回到 cookie。
localStorage与sessionStorage
浏览器家族中最早支持的内置本地缓存技术,二者 API 完全相同(getItem/setItem/removeItem/clear),只差生命周期:
- localStorage: 持久化本地存储。除非主动删除数据,否则数据是永远不会过期的。
- sessionStorage: 仅存储一个会话(session)中的数据,即只有在同一个会话中的页面,才能访问会话数据。并且当会话结束后数据也随之销毁
KV 存储的局限
- 安全风险:localStorage 数据以明文形式存储,容易受到 XSS 攻击,攻击者可以通过注入恶意脚本轻松获取存储的敏感信息。
- 同步阻塞操作:localStorage 的读写操作是同步的,会阻塞主线程,在存储大量数据时可能导致性能问题和界面卡顿。
- 存储容量有限:大多数浏览器将 localStorage 的存储上限设为 5MB,无法满足现代复杂应用的需求。
- 只能存储字符串:需要手动序列化和反序列化复杂数据结构,增加了代码复杂度和出错可能。
- 缺乏高级查询能力:只能按键精确取值,无法按条件查询、排序、建索引——"字典"终究不是"数据库"。
IndexedDB:浏览器里的数据库
容量上限高(通常数百 MB 以上,部分浏览器可达可用磁盘空间的比例),API 全异步。要点:
- 对象仓库(object store):直接存 JavaScript 对象,无需手动序列化;支持 String、Array、Object、File、Blob、ArrayBuffer、ImageData 等
- 索引与查询:可对任意字段建索引,用游标(cursor)按范围遍历——这是它与 KV 存储的本质区别
- 事务机制:读写必须在事务中进行,保证数据完整性
- 异步 API:基于事件(新版提供 Promise 化接口),不阻塞主线程;可与 Web Workers 配合,把数据处理隔离在主线程之外
- 遵循同源策略,持久化优先级高于 localStorage
KV 与数据库的分野,是后端世界的老问题在浏览器的重演:Redis 式 KV 胜在简单迅捷,SQLite/MySQL 式数据库胜在结构与查询。前端同样如此——简单偏好用 KV,业务数据用 IndexedDB。 历史注脚:浏览器曾内置过 SQL 风格的 WebSQL(真正的 SQLite),因标准化停滞已废弃,其角色由 IndexedDB 接替;如今要用 SQL 语法操作 IndexedDB,可借助 sql.js(SQLite 编译为 WebAssembly)等方案。
封装工具
原生 IndexedDB API 以事件为基础,写法繁琐,实践中常用封装:
- localForage — 提供 localStorage 风格的简单 API,底层自动选用 IndexedDB/WebSQL/localStorage,"KV 的易用 + 数据库的容量"
- idb — IndexedDB 的极薄 Promise 封装
- Dexie — 流行的 IndexedDB 完整封装,支持链式查询