选存储说到底是先看数据量、生命周期和要不要同步到服务端,这三点定了,方案基本就定了。
Q1: Cookie / LocalStorage / SessionStorage / IndexedDB 有什么区别?
1
1994年: Cookie 的诞生
Netscape 引入 Cookie 解决 HTTP 无状态的问题——服务器需要一种机制来识别用户。Cookie 的核心设计是每次 HTTP 请求自动携带,让服务器能通过 Cookie 识别用户身份。
2
致命痛点: Cookie 的局限
Cookie 单条约 4KB(4096 字节,含名值),每次请求都增加带宽,且有 CSRF 风险。对于大量客户端数据(如离线缓存、用户偏好设置),Cookie 力不从心。
3
HTML5 的存储革命: Web Storage
HTML5 引入了 LocalStorage(永久存储,通常 5-10MB)和 SessionStorage(标签页隔离,通常 5-10MB),同步 API,使用简单。但它们只能存字符串,无法存储结构化数据,且同步读写会阻塞主线程。
4
IndexedDB: 大规模结构化数据
IndexedDB 是浏览器内置的 NoSQL 数据库,支持事务、索引、游标,容量受浏览器配额限制(通常远大于 Web Storage)。异步 API 不阻塞主线程,适合大量结构化数据。但 API 复杂,通常用
idb 或 localForage 封装。5
关键权衡: 数据量, 生命周期, 服务端同步
选择存储方案要看三个维度:数据量决定容量需求,生命周期决定持久化策略,是否需要和服务端同步决定用 Cookie 还是客户端存储。
不区分存储方案
就像一个仓库里所有东西都堆在门口的纸箱里(Cookie)。纸箱只有 4KB 空间,每次发货都要把纸箱里的东西一起寄出去(每次请求自动携带),仓库里堆了几 TB 的数据根本放不下。
按需求选择存储方案
就像一个现代化仓库有了分区管理:门口放快递单(Cookie,小但自动随货发送),货架放常用物品(LocalStorage,中等容量随时取用),档案室放大量文件(IndexedDB,容量大但需要按流程存取)。每个区域的大小、访问方式、生命周期都不同,各司其职。
Q2: Cookie 的核心机制是什么?
Cookie 的本质是服务器通过 HTTP 响应头写入、浏览器通过 HTTP 请求头携带的键值对。核心机制只有 3 步:Q3: LocalStorage 和 IndexedDB 有什么区别?
基础梳理
专家视角深度剖析
很多人能说出 LocalStorage 和 IndexedDB 的区别,但实际更在意的是:在什么场景下必须用 IndexedDB?LocalStorage 的同步 API 会带来什么问题? LocalStorage 是同步 API——读写操作会阻塞主线程。对于小量数据(几 KB),阻塞时间可以忽略。但如果存储了 1MB 以上的数据,读写操作可能导致明显的卡顿。Chrome 的 LocalStorage 底层用 LevelDB 实现,按 origin(协议+域名+端口)隔离。 IndexedDB 是异步 API——操作在浏览器内部的独立线程执行,不占用页面主线程。它支持事务(自动提交)、索引(多字段查询)、游标(遍历大数据集),适合大量结构化数据。但 IndexedDB 的 API 非常复杂,通常用idb(Jake Archibald 的封装库)或 localForage(提供类似 LocalStorage 的简单 API)。
Q4: SessionStorage 有什么特殊行为?
SessionStorage 的核心特点:标签页隔离。 同一个 URL 在不同标签页有独立的 SessionStorage——这和 Cookie/LocalStorage 不同,它们在同一域名下共享。 关键行为:底层源码:Chromium 是如何实现存储的?
Chromium 的存储架构是怎么分层的?
Chromium 的存储架构统一由 StoragePartition 管理(详见 Chromium 源码:storage_partition_impl.cc):
StoragePartitionImpl 管理。LocalStorage 和 IndexedDB 底层都用 LevelDB(Google 的键值存储引擎),但使用方式不同:LocalStorage 是同步 API,在渲染进程主线程执行;IndexedDB 是异步 API,在独立线程执行,不阻塞主线程。
LocalStorage 的存储配额是怎么管理的?
详见 Chromium 源码:quota_settings.cc:
setItem 和事务操作会抛出 QuotaExceededError。可以用 navigator.storage.estimate() 查询已用空间和总配额,用 navigator.storage.persist() 申请持久化存储——它返回 Promise<boolean>,成功后数据不会被浏览器在空间紧张时自动清理。
及格回答 vs 满分回答
问题:“说说前端存储方案的区别”
及格回答(60-70分):“Cookie 单条约 4KB,每次请求自动携带。LocalStorage 5MB 左右,永久存储。SessionStorage 关闭标签页就没了。IndexedDB 受配额限制,异步 API。”问题出在:背了参数但不理解选型逻辑。 满分回答(90-100分):
选择存储方案要看三个维度:数据量、生命周期、是否需要和服务端同步。Cookie 的核心价值是自动携带——每次 HTTP 请求都会带上,适合身份认证。但 Cookie 单条约 4KB(4096 字节,含名值),每次请求增加带宽,且有 CSRF 风险。现代方案常用 JWT + Authorization Header 替代 Cookie 做认证。[1]
LocalStorage 是同步 API——读写操作会阻塞主线程。对于小量数据(几 KB)没问题,但存储 1MB 以上数据时读写可能导致卡顿。SessionStorage 的特点是标签页隔离——同一 URL 在不同标签页有独立的 SessionStorage,适合表单暂存。window.open 打开的新窗口会复制(不是共享)SessionStorage。[2]
IndexedDB 是异步 API,适合大量结构化数据。支持事务(自动提交)、索引(多字段查询)、游标(遍历大数据集)。但 API 复杂,通常用idb或localForage封装。IndexedDB 的事务有一个坑:所有请求完成后自动提交,不能像 SQL 那样手动 begin/commit。如果事务中await了非 IndexedDB 的异步操作(如网络请求),事务可能已经自动提交了。[3]
Chromium 中 LocalStorage 和 IndexedDB 底层都用 LevelDB,但 LocalStorage 是同步 API 在主线程执行,IndexedDB 是异步 API 在独立线程执行。存储配额由 Quota 系统统一管理,LocalStorage 每个 origin 约 5MB,IndexedDB 和 Cache Storage 共享配额池,Chrome 中单源总配额通常不超过磁盘总量的约 60%。配额不足时setItem会抛QuotaExceededError。
常见追问
题目来源于真实面经(字节/腾讯/阿里前端面试、牛客网、haizlin/fe-interview),按难度递进。
LocalStorage 存满了会怎样?怎么处理?
LocalStorage 存满了会怎样?怎么处理?
答题要点:
结合具体错误场景和解决方案解释。高分回答:
“LocalStorage 存满时,注意:旧版 Safari 的无痕模式曾把 LocalStorage 配额限制为 0,任何写入都会抛
setItem 会抛出 QuotaExceededError。不同浏览器限制不同——通常是 5MB-10MB,按 origin 隔离。处理方式:
1)预防:用 navigator.storage.estimate() 查询已用空间和配额,在接近上限时主动清理。
2)捕获异常:try-catch 包裹 setItem,在捕获到 QuotaExceededError 时清理过期数据。
3)降级方案:数据量大时迁移到 IndexedDB——它受 Quota 系统统一管理,单源配额通常远大于 LocalStorage。QuotaExceededError;不同版本行为可能变化,仍需 try-catch 兜底。”IndexedDB 的事务有什么特点?为什么容易踩坑?
IndexedDB 的事务有什么特点?为什么容易踩坑?
答题要点:
指出自动提交机制和异步操作的冲突。高分回答:
“IndexedDB 的事务有两个核心特点:1)自动提交:当所有请求完成后、没有新的请求时,事务自动提交。不能像 SQL 那样手动 begin/commit/rollback。这是为了简化 API,但也是最容易踩坑的地方。2)异步操作的坑:如果事务中 事务失败时自动回滚。可以通过
await 了非 IndexedDB 的异步操作(如网络请求),事务可能在等待期间自动提交。tx.abort() 手动回滚;用 idb 封装时也可以 await tx.done 等待完成。”Service Worker 的 Cache Storage 和浏览器 HTTP 缓存有什么区别?
Service Worker 的 Cache Storage 和浏览器 HTTP 缓存有什么区别?
答题要点:
对比两种缓存机制的控制权和适用场景。高分回答:
“Service Worker 的 Cache Storage 和浏览器 HTTP 缓存是两套独立的系统:HTTP 缓存:由浏览器自动管理,遵循
Cache-Control、ETag 等响应头。开发者只能通过 HTTP 头控制缓存策略,无法用 JS 精细控制。适用于静态资源的自动缓存。Cache Storage:由 Service Worker 通过 Cache API 完全控制。开发者可以精确决定缓存什么、什么时候缓存、什么时候清除。适用于离线应用(PWA)和自定义缓存策略。关键区别:
1)控制权:HTTP 缓存由浏览器自动管理,Cache Storage 由 JS 完全控制。
2)生命周期:HTTP 缓存随浏览器清理,Cache Storage 可以持久化。
3)作用域:HTTP 缓存在网络层拦截,Cache Storage 在 Service Worker 中拦截。
4)配合使用:Service Worker 可以先查 Cache Storage,未命中再走网络请求(自动触发 HTTP 缓存)。典型的 PWA 缓存策略:Service Worker 在 install 事件中预缓存关键资源,在 fetch 事件中拦截请求,优先返回缓存内容(Cache-First),或者先返回缓存再更新(Stale-While-Revalidate)。“延伸阅读与引用参考
- MDN: Web Storage API:Mozilla 对 LocalStorage 和 SessionStorage 的权威参考,含 API 说明和使用限制。[1]
- Jake Archibald: IndexedDB 详解:深度剖析了 IndexedDB 的事务机制、异步模型和常见陷阱。[2]
- Chromium 存储架构文档:Chromium 对存储后端架构的最权威说明,含配额管理和数据隔离机制。[3]
