你有没有想过,为什么刷新页面后,有些网站还能记住你的登录状态?为什么购物车里的商品关掉浏览器再打开还在?今天我们就来聊聊浏览器里的“记忆术”——本地存储。从简单的钥匙串localStorage,到能装下整个图书馆的IndexedDB,总有一款适合你。
前言
想象一下,你每次去网吧上网,都要重新登录所有账号、重新设置主题、重新添加购物车——是不是想砸电脑?还好,浏览器有“记忆功能”。它能在你的电脑里存点东西,下次再来时直接拿出来用。
这个“记忆功能”就是Web存储。今天我们就来盘点一下浏览器提供的几种存储方式:localStorage、sessionStorage、cookie,以及能存视频、存大文件的IndexedDB。看完你就能根据场景选对工具,再也不用担心数据“蒸发”了。
一、localStorage:永不过期的便利贴
localStorage是一个挂在window上的对象,它存的数据没有过期时间,除非你手动清除或者用户清理浏览器缓存,否则会一直待在那里。
基本用法
// 存数据(键值对,值必须是字符串)
localStorage.setItem('username', '张三');
localStorage.setItem('theme', 'dark');
// 取数据
const name = localStorage.getItem('username'); // '张三'
// 删除某条
localStorage.removeItem('theme');
// 全部清空
localStorage.clear();
// 获取存储数量
console.log(localStorage.length);
存对象怎么办?
localStorage只能存字符串,所以对象要先转成JSON:
const user = { name: '张三', age: 18 };
localStorage.setItem('user', JSON.stringify(user));
// 读取时解析
const stored = JSON.parse(localStorage.getItem('user'));
容量限制
大多数浏览器限制5MB~10MB,够存一些配置、用户信息、小量缓存。
特点总结
- 同步:操作是同步的,会阻塞主线程(但一般很快)。
- 同源:同一域名下所有页面共享(包括不同标签页)。
- 永久:除非手动清除。
- 仅客户端:不会自动发送到服务器。
二、sessionStorage:标签页关闭就消失的临时工
sessionStorage和localStorage的API一模一样,但生命周期不同:它只存在于当前标签页。关掉标签页,数据就没了。刷新页面还在,但新开标签页(即使是同一个网站)会得到一个新的sessionStorage。
// 用法完全一样
sessionStorage.setItem('tempData', '临时值');
适用场景:表单临时草稿、当前页面的中间状态、不希望跨页面共享的敏感信息。
三、cookie:老前辈,但有点“重”
cookie是最早的浏览器存储机制,但如今除了会话管理(登录态)和少量用户追踪,大部分场景已被localStorage替代。
特点
- 容量小:每个cookie 4KB 左右。
- 自动携带:每次HTTP请求都会把cookie发给服务器(增加带宽消耗)。
- 可设置过期时间。
- 可标记
HttpOnly(禁止JS读取,防XSS)、Secure(仅HTTPS)、SameSite(防CSRF)。
// 设置cookie(繁琐)
document.cookie = "username=张三; expires=Thu, 18 Dec 2026 12:00:00 UTC; path=/";
// 读取cookie(需要自己解析)
console.log(document.cookie);
现在主流做法:用localStorage存非敏感数据,用httpOnly cookie存登录凭证。
四、IndexedDB:浏览器里的“小数据库”
如果你要存的东西很大(几百MB),或者需要复杂的查询、索引、事务,那么localStorage就不够用了。这时候请出IndexedDB——一个运行在浏览器里的非关系型数据库。
特点
- 容量大:通常250MB+,甚至更多(取决于浏览器)。
- 异步API:基于Promise或回调,不阻塞主线程。
- 支持索引、游标、事务。
- 可以存储File、Blob、ArrayBuffer等二进制数据。
快速上手
IndexedDB的API比较原始,不过我们可以封装一下。
// 1. 打开/创建数据库
const request = indexedDB.open('MyDatabase', 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
// 创建一个对象仓库(类似表),指定主键
const store = db.createObjectStore('users', { keyPath: 'id' });
// 创建索引,用于快速查询
store.createIndex('name', 'name', { unique: false });
};
request.onsuccess = (event) => {
const db = event.target.result;
console.log('数据库打开成功');
// 后续增删改查都用这个db对象
};
request.onerror = (event) => {
console.error('数据库打开失败', event.target.error);
};
增删改查
// 添加数据(在onsuccess里拿到db)
const transaction = db.transaction(['users'], 'readwrite');
const store = transaction.objectStore('users');
const addRequest = store.add({ id: 1, name: '张三', age: 18 });
addRequest.onsuccess = () => console.log('添加成功');
addRequest.onerror = (e) => console.error('添加失败', e.target.error);
// 查询
const getRequest = store.get(1);
getRequest.onsuccess = () => console.log(getRequest.result);
// 更新(使用put,如果存在则覆盖)
store.put({ id: 1, name: '李四', age: 20 });
// 删除
store.delete(1);
使用游标遍历
const range = IDBKeyRange.bound(1, 10); // id从1到10
store.openCursor(range).onsuccess = (e) => {
const cursor = e.target.result;
if (cursor) {
console.log(cursor.value);
cursor.continue(); // 继续下一个
}
};
现代封装:localForage
原生IndexedDB API太啰嗦,推荐用localForage这个库,它提供了类似localStorage的简洁API,但背后自动选择IndexedDB、WebSQL或localStorage。
// 使用localForage
import localforage from 'localforage';
await localforage.setItem('user', { name: '张三' });
const user = await localforage.getItem('user');
五、四种存储方式对比
| 特性 | localStorage | sessionStorage | cookie | IndexedDB |
|---|---|---|---|---|
| 容量 | 5-10MB | 5-10MB | 4KB | 几百MB |
| 生命周期 | 永久 | 标签页关闭 | 可设置过期 | 永久 |
| 跨标签页 | 是 | 否 | 是 | 是 |
| 异步 | 同步 | 同步 | 同步 | 异步 |
| 自动发到服务器 | 否 | 否 | 是(每次请求) | 否 |
| 数据类型 | 字符串 | 字符串 | 字符串 | 任意(结构化克隆) |
| 查询能力 | 无 | 无 | 无 | 索引、游标 |
六、选型指南:到底用哪个?
- 简单键值对,少量数据:
localStorage,比如用户偏好设置、主题、是否首次访问。 - 临时数据,只在一个页面用:
sessionStorage,比如多步骤表单的暂存。 - 登录凭证:
httpOnly cookie(安全)配合后端。 - 大量结构化数据、离线应用:
IndexedDB,比如邮件客户端、笔记应用、缓存API数据。 - 需要与后端自动同步:
cookie或Authorization头(用localStorage存token也行,但要注意XSS)。
七、避坑指南
1. localStorage 的同步阻塞
大量数据存取会阻塞UI,建议不要存超过几MB,或改用IndexedDB。
2. 隐私模式
Safari的隐私模式下,localStorage和IndexedDB可能不可用或容量极低,要写try-catch降级。
3. 序列化问题
localStorage存对象会丢失原型链、函数、Symbol、循环引用。用JSON.stringify前确保数据可序列化。
4. 安全提醒
永远不要把敏感信息(如密码、token)明文存在localStorage,因为任何JS都能读到(XSS攻击)。token建议用httpOnly cookie或短时效+refresh机制。
5. IndexedDB 版本升级
当修改数据库结构时,需要增加版本号,并在onupgradeneeded里处理旧数据迁移,否则会报错。
八、总结:存储就像选工具箱
- localStorage:日常杂货,随手放。
- sessionStorage:临时工,关窗走人。
- cookie:老古董,特殊场合用。
- IndexedDB:重武器,存大文件、复杂查询。
掌握了这些,你就可以在浏览器里随心所欲地存数据了。明天我们将继续前端工程化的旅程,聊聊Cookie与Session的区别,以及现代认证方案JWT。
如果你觉得今天的存储全家桶够实用,点个赞让更多人看到。我们明天见!