存储中的概念
存储配额、持久化与逐出
发布于
存储配额限制来源能写入多少数据;持久化主要决定存储桶能否由浏览器自动清理;逐出则是浏览器按清理策略删除数据。配额仍由浏览器实现决定,并可把 persistent-storage 权限纳入计算,因此 persist() 成功后来源配额也可能改变。例如,Firefox 会对获准持久化的来源应用更高上限。
页面兼容表读取 Persistent Storage 中 api.StorageManager.persist 的数据。
工作原理
链接到“工作原理”一节Storage Standard 为每个 storage shelf 设置默认存储桶。本地存储桶的模式可为 best-effort 或 persistent。规范把 usage 定义为由实现决定的粗略估值,把 quota 定义为由实现决定的保守估值。浏览器还会使用压缩、去重和隐私保护,因此 estimate() 返回的数值不是磁盘占用的精确读数(Storage Standard,storage.spec.whatwg.org)。
持久化可保护本地存储桶,使用户代理不能在来源或用户未参与的情况下清除它;用户仍可主动删除这些数据。persist() 请求 persistent-storage 权限,并以布尔值报告默认存储桶是否已经持久化。persisted() 只读取模式,不请求变更(Storage Standard,storage.spec.whatwg.org)。
逐出针对浏览器按来源管理的存储,包括 IndexedDB、Cache Storage 和 Origin Private File System。MDN 记载,浏览器逐出某来源时会一并删除其受管理的数据,不会只裁掉某个数据库。Storage Standard 同样要求清理整个存储桶(Storage quotas and eviction criteria,developer.mozilla.org;Storage Standard,storage.spec.whatwg.org)。
| 决策 | 要回答的问题 | 浏览器信号 | 应用处理 |
|---|---|---|---|
| 配额 | 下一次写入能否容纳? | navigator.storage.estimate() 给出近似的 usage 与 quota。 |
捕获写入错误,提供清理或服务端恢复。 |
| 持久化 | 浏览器能否自动清理这个存储桶? | persisted() 报告模式,persist() 请求变更。 |
在结果为 true 前,关键的本地数据仍须可恢复。 |
| 逐出 | 浏览器需要空间时会怎样? | Storage Standard 没有定义逐出事件。 | 启动时检查必要记录和缓存,重建缺失数据。 |
Chromium 策略
链接到“Chromium 策略”一节Chrome 的存储指南写明:Chrome 可让浏览器使用总磁盘空间的 80%,单个来源可使用 60%。空间不足时,浏览器按最近最少使用顺序清除 best-effort 来源。其他 Chromium 浏览器的策略可能不同(Storage for the web,web.dev)。
Chrome 等 Chromium 浏览器通常根据站点互动情况自动批准或拒绝持久化请求,不显示权限提示。返回 false 只表示存储桶仍是 best-effort 模式,不代表刚才的写入已经失败(Storage quotas and eviction criteria,developer.mozilla.org)。
Firefox 策略
链接到“Firefox 策略”一节MDN 记载,Firefox 的 best-effort 上限取两者中较小值:用户配置所在磁盘总容量的 10%,或同一站点下各来源共享的 10 GiB 分组上限。获准持久化的来源最多可用总磁盘空间的 50%,上限 8 TiB,且不受分组上限约束。Firefox 会在站点请求持久化时询问用户;发生存储压力时,它跳过持久化来源,按最近最少使用顺序逐出 best-effort 来源(Storage quotas and eviction criteria,developer.mozilla.org)。
配额按磁盘总容量计算,不按可用空间计算。因此,估值可能大于设备实际还能写入的空间。即使估值看起来充足,代码仍须处理写入失败。
WebKit 策略
链接到“WebKit 策略”一节WebKit 分别规定来源配额和总体配额。从 Safari 17.0,以及 iOS 17、iPadOS 17 和 macOS Sonoma 的 WebKit App 开始,浏览器 App 中单个来源最多可用总磁盘空间的 60%,总体配额最多为 80%;嵌入网页内容的其他 App 上限更低。iOS 主屏 Web App 或 macOS Dock Web App 与浏览器 App 中的同站点使用相同的来源配额和总体配额(Updates to Storage Policy,webkit.org)。
WebKit 列出的数据删除路径包括超过总体配额、系统存储压力和 Intelligent Tracking Prevention。ITP 文档记载,从 iOS、iPadOS 13.4 和 macOS Safari 13.1 起,站点连续七个 Safari 使用日没有用户互动后,其脚本可写存储会被删除;主屏 Web App 单独计算使用日(Full Third-Party Cookie Blocking and More,webkit.org)。
第一个示例读取模式与估值,但不会把任一结果当作后续写入成功的保证。
检查配额与持久化模式
链接到“检查配额与持久化模式”一节async function readStorageState() { if (!navigator.storage?.estimate) { return { supported: false, persisted: false }; }
const { usage = 0, quota = 0 } = await navigator.storage.estimate(); const persisted = navigator.storage.persisted ? await navigator.storage.persisted() : false;
return { supported: true, usage, quota, persisted };}
readStorageState().then((state) => console.log(state));不支持时,界面可以根据回退结果显示“不可用”。支持时,usage 与 quota 仍是以字节表示的估值,应用不应据此计算下一笔事务的保证容量。
第二个示例分别处理持久化结果和配额错误。若本地存储无法接受草稿,它会把内容保存到服务端。
写入超过配额时恢复
链接到“写入超过配额时恢复”一节async function saveDraft(draft) { const persistent = navigator.storage?.persist ? await navigator.storage.persist() : false;
try { await draftsDatabase.put(draft); return { saved: 'local', persistent }; } catch (error) { if (error?.name !== 'QuotaExceededError') throw error; await fetch('/api/drafts', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(draft), }); return { saved: 'server', persistent }; }}持久化结果与写入结果互不替代。persist() 返回 false 时,写入仍可能成功;QuotaExceededError 则进入 Chrome 与 WebKit 存储指南所述的显式恢复分支。
下次启动时,应检查应用所需的具体记录,不要只凭 estimate() 推断是否发生逐出。数据库缺失也可能源于首次访问或用户主动清理。逐出与尽力而为存储 说明恢复边界,Safari 对脚本可写存储的 7 天上限 说明 WebKit 的主动删除路径。
另请参阅
链接到“另请参阅”一节- Storage Standard(storage.spec.whatwg.org)
- Updates to Storage Policy(webkit.org)
- Storage for the web(web.dev)
- StorageManager.persist() 与 persisted()
- StorageManager.estimate()
- 逐出与尽力而为存储
- Persistent Storage 兼容性
规范
| 规范 | 状态 |
|---|---|
| Persistent Storage(持久化存储) | WHATWG 现行标准 |
- 图例
- 支持
- 部分支持
- 需开启标志
- 不支持
- 未知
| 浏览器 / 平台 | 支持 | 版本 | 置信度 | 来源 | 备注 |
|---|---|---|---|---|---|
| Chrome (Desktop)# | 支持 | 55 | 高 | 来源 | — |
| Chrome (Android)# | 支持 | 55 | 高 | 来源 | 1 |
| Edge (Desktop)# | 支持 | 79 | 高 | 来源 | 2 |
| Firefox (Desktop)# | 支持 | 57 | 高 | 来源 | — |
| Firefox (Android)# | 支持 | 57 | 高 | 来源 | 3 |
| Safari (macOS)# | 支持 | 15.2 | 高 | 来源 | — |
| Safari (iOS)# | 支持 | 15.2 | 高 | 来源 | 4 |
| Samsung Internet# | 支持 | 6.0 | 高 | 来源 | 5 |
| WebView (Android)# | 支持 | 55 | 高 | 来源 | 6 |
- 由 browser-compat-data 镜像自 Chrome 的数据推导。
- 由 browser-compat-data 镜像自 Chrome 的数据推导。
- 由 browser-compat-data 镜像自 Firefox 的数据推导。
- 由 browser-compat-data 镜像自 Safari 的数据推导。
- 由 browser-compat-data 镜像自 Chrome Android 的数据推导。
- 由 browser-compat-data 镜像自 Chrome Android 的数据推导。