浏览器存储选型 cookie、localStorage、IndexedDB
MidnightDeal
6 分钟阅读
浏览器存储选型 cookie、localStorage、IndexedDB
三者都能在浏览器里存数据,但容量、生命周期、访问方式差出一个数量级。选错存储只会在后续扩展时反复返工:一开始用 localStorage 存点偏好,后来要存离线草稿发现 5MB 不够,再搬去 IndexedDB 又得重写读写逻辑。提前看清三者边界,能省掉一次痛苦的迁移。
一张表看差异
| 能力 |
cookie |
localStorage |
IndexedDB |
| 容量量级 |
约 4KB |
约 5MB |
数百 MB(受磁盘与配额策略影响) |
| 随请求发送 |
是(同源请求自动带) |
否 |
否 |
| API 形态 |
字符串 |
同步键值对 |
异步事务数据库 |
| 典型用途 |
会话凭证 |
偏好设置 |
离线缓存、列表数据 |
| 生命周期 |
可设过期 |
永久(除非清除) |
永久(除非清除) |
这张表的重点是"随请求发送"一行:只有 cookie 会自动附着到每个同源请求,这正是它存在的理由,也是它体积的硬约束。另外两者再大也不会偷偷占用请求带宽。
cookie:为会话而生的折衷
cookie 设计初衷是让服务端维持状态,每次同源请求自动带上。这既是优点也是负担:
document.cookie = 'token=abc; path=/; max-age=3600; secure';
问题在于体积上限仅约 4KB,且每个请求都携带,高频小请求会徒增流量。一个页面如果挂了十几个资源请求,cookie 头会被每个请求重复发送,浪费相当可观。现代实践里凭证尽量放 httpOnly cookie 防 XSS 读取,但纯前端读不到,需要时得走接口换取。边界:cookie 的 SameSite 默认值在近年浏览器变严格,跨站场景不显式设置可能发不出去,需要按业务显式声明 Lax 或 None;涉及跨站还要配 Secure。还有 Domain 和 Path 决定 cookie 的可见范围,配错会出现"登录态子域拿不到"的问题,排查起来很隐蔽。
localStorage:简单键值对的陷阱
同步 API,读写都阻塞主线程:
localStorage.setItem('theme', 'dark');
const theme = localStorage.getItem('theme');
容量约 5MB,同源共享,持久化到磁盘,除非主动清除或用户清缓存才消失。踩坑点:它是同步的,存大字符串会卡 UI,尤其是在低端移动设备上存几 MB 的 JSON 会明显顿一下。部分浏览器在隐私模式下禁用 localStorage,直接抛异常,必须用 try/catch 包裹,否则整页脚本会中断。还有同源下不同标签页不隔离,一个页面改动另一个能监听到 storage 事件,可借此做跨标签页同步,但反向也要小心一个标签页清空导致另一个数据丢失。字符串序列化也是隐性成本:存对象要先 JSON.stringify,取回还要 parse,结构一变就容易解析出 undefined。
IndexedDB:结构化与异步
当要存列表、离线缓存、二进制(Blob/ArrayBuffer)时,localStorage 不够用。IndexedDB 是事务型数据库,异步、容量大:
const req = indexedDB.open('app', 1);
req.onsuccess = (e) => {
const db = e.target.result;
const tx = db.transaction('tasks', 'readwrite');
tx.objectStore('tasks').put({ id: 1, text: 'demo' });
};
代价是 API 冗长、回调嵌套深,通常会包一层 Promise 或用库封装。它支持索引查询、游标遍历,适合存结构化记录而非简单键值。边界:写大量小记录时逐条事务效率差,应批量提交;隐私模式下部分浏览器对 IndexedDB 也有限制,需要降级到 localStorage 或内存。还有配额:浏览器按源分配磁盘配额,存满会触发 QuotaExceededError,读写都要处理这个异常,否则离线场景会静默失败。版本升级(open 的第二个参数变化)会触发 onupgradeneeded,在这里建表改结构,否则旧库结构不匹配会一直报错。
三者之外的现实约束
除了技术差异,还有两个常被忽略的约束。一是同站多页面共享:localStorage 和 cookie 按源共享,IndexedDB 也按源隔离,所以同源下的不同子应用会互相读到彼此的数据,做命名前缀避免冲突是必要的。二是用户清缓存或开无痕模式时,三类存储都可能被清空或禁用,任何"本地一定有"的假设都会在某次用户操作后被打破。因此关键数据永远要有服务端来源,本地存储只承担"加速"和"离线兜底"的角色,而非唯一真相。
选型建议
- 需要服务端会话、要随请求自动发送的凭证:cookie。
- 小体量、结构简单、要长期存的偏好设置:localStorage(记得 try/catch)。
- 列表数据、离线缓存、大体积或二进制:IndexedDB。
经验上,移动端还要考虑"清除数据"会把三者一起抹掉,关键离线数据要有服务端兜底,不能假设本地一定在。三者都不是安全边界,敏感信息不该明文落本地;即便 localStorage 看起来"私有",也架不住 XSS 一把梭。存储选型本质是"容量 × 访问方式 × 生命周期"三维度的取舍,先把这三个维度列清楚,选型自然就出来了。
浏览 0
点赞 0
评论 0