存储 · API
StorageManager.estimate()
发布于
navigator.storage.estimate() 解析为两个字节数:当前源已经占用的 usage,以及它最多可以占用的保守上限 quota。上限是浏览器在调用时按磁盘比例算出来的,不是常量,所以只能在运行时读取,不能写死在代码里。
navigator.storage.estimate()该方法不接受参数,返回一个以 StorageEstimate 字典兑现的 Promise。窗口和 worker(Service Worker 内为 self.navigator.storage)都可以调用,仅限安全上下文(BCD api.StorageManager.estimate:Chrome 61、Firefox 57、Safari 17)。
无。
Promise 兑现为一个对象,含两个标准成员和一个 Chromium 扩展成员。
| 成员 | 类型 | 含义 |
|---|---|---|
usage |
number | 该源在受配额管理的存储(Cache Storage、IndexedDB、OPFS、Service Worker 注册)中占用的字节数。经过取整和填充,不是精确账目。 |
quota |
number | 该源总共可用的字节数。保守估计,随磁盘填满而缩小。 |
usageDetails |
object | 仅 Chromium(BCD api.StorageManager.estimate.usageDetails)。按存储系统细分的 usage;用量为 0 的系统会被省略,读取前先判断键是否存在。 |
Storage 标准允许浏览器用压缩、去重和填充对这两个数字做混淆,避免页面从精确字节数推断磁盘容量或其他站点的数据。Chromium 对不透明响应的填充最为明显:一条几 KB 的跨源 no-cors 响应会让 usage 增加约 7 MB(Understanding storage quota,developer.chrome.com)。
配额如何计算
Section titled “配额如何计算”每个引擎都从磁盘容量推导 quota,但公式不同(Storage quotas and eviction criteria,developer.mozilla.org)。
| 引擎 | 每源配额 | 所有源的总上限 |
|---|---|---|
| Chromium(Chrome、Edge) | 磁盘总容量的 60%,尽力而为与持久化模式相同。无痕模式降到约 5%;开启「关闭所有窗口时清除 Cookie 和网站数据」后上限约 300 MB(Storage for the web,web.dev)。 | 磁盘总容量的 80% |
| Firefox | 磁盘总容量的 10% 与 10 GiB 分组上限(同一站点 eTLD+1 下所有源共享)两者取小。持久化源可用磁盘的 50%,上限 8 TiB,且不受分组上限约束。 | 可用磁盘的 50% |
| WebKit(Safari 17、iOS 17、macOS 14) | 浏览器应用内约为磁盘总容量的 60%,其他应用的 WKWebView 内约 15%;跨源 frame 得到嵌入方配额的 10%。添加到主屏幕或 Dock 的 Web App 沿用浏览器的数值(Updates to Storage Policy,webkit.org)。 |
浏览器应用内为磁盘的 80%,其他应用内为 20% |
Safari 17 之前,每个源起始配额为 1 GiB,用满后 Safari 询问用户并按 200 MB 递增。旧版 WebKit 报告的 quota 会在提示之后变化,这也是每次大写入前重读而不要缓存它的又一个理由。
| 异常 | 触发条件 |
|---|---|
TypeError |
浏览器无法为该源获取存储架:源是不透明源(没有 allow-same-origin 的沙箱 <iframe>、data: 文档),或用户已为该站点禁用存储。Promise 被拒绝,方法本身不抛出。 |
空间不足不是 estimate() 的异常。超过 quota 的写入会在执行写入的存储里失败:cache.put() 以 QuotaExceededError DOMException 拒绝,IndexedDB 请求触发 error 事件、request.error.name === "QuotaExceededError" 并中止事务。
三个示例分别用于展示用量、在大写入前决策,以及在方法缺失时降级。
读取估计值并显示预算行
Section titled “读取估计值并显示预算行”两个成员足以显示该源用了多少。先做除法再格式化即可,两者都是字节数,普通浮点运算足够精确。
const { usage, quota } = await navigator.storage.estimate();const percent = ((usage / quota) * 100).toFixed(1);console.log(`${(usage / 1048576).toFixed(1)} MiB / ${(quota / 1073741824).toFixed(1)} GiB(${percent}%)`);在 Chromium 的 60% 规则下,桌面机的 quota 通常是几百 GB;接近满盘的手机则小得多。适合一台设备的预算不一定适合另一台。
大下载前检查余量
Section titled “大下载前检查余量”在已知大小的写入之前立即调用 estimate(),并为上文的填充留出余量。写入仍然失败时,捕获 QuotaExceededError,释放空间后重试一次,而不是让整个操作失败。
async function cacheLargeAsset(cache, url, expectedBytes) { const { usage, quota } = await navigator.storage.estimate(); if (quota - usage < expectedBytes * 1.2) { await pruneOldEntries(cache); } try { await cache.add(url); } catch (err) { if (err.name !== 'QuotaExceededError') throw err; await pruneOldEntries(cache); await cache.add(url); }}20% 的余量是针对取整的经验值,不来自任何规范;真正重要的是清理后的重试,因为一秒前读到的 quota 在一台正在同时下载照片的设备上已经过期。
检测支持并降级
Section titled “检测支持并降级”不安全源上没有 navigator.storage,早于「语法」一节所列版本的浏览器也没有。把方法缺失当作「预算未知」,乐观写入并依赖存储自身的 QuotaExceededError。
async function storageBudget() { if (!('storage' in navigator) || typeof navigator.storage.estimate !== 'function') { return null; // 预算未知:退回到在写入时捕获配额错误 } try { return await navigator.storage.estimate(); } catch (err) { if (err.name === 'TypeError') return null; // 不透明源或存储被禁用 throw err; }}返回 null 让调用方只走一条路径:尝试写入并处理失败。这件事它本来就必须做,因为估计值只是参考。
- Storage: estimate() method(whatwg.org)
- Updates to Storage Policy(webkit.org)
- Storage quotas and eviction criteria(developer.mozilla.org)
- navigator.storage.persist()
- 逐出与尽力而为存储
- CacheStorage 与 caches 全局对象
规范
| 规范 | 状态 |
|---|---|
| 无。 | |