估算可用存储空间

tl;dr

Chrome 61 将会陆续将更多浏览器推出, 存储容量和可用容量:

if ('storage' in navigator && 'estimate' in navigator.storage) {
  navigator.storage.estimate().then(({usage, quota}) => {
    console.log(`Using ${usage} out of ${quota} bytes.`);
  });
}

现代 Web 应用和数据存储

考虑到现代 Web 应用的存储需求,以下做法会很有帮助: 将存储内容分为两类:加载所需的核心数据 Web 应用,以及一次有意义的用户互动所需的数据, 应用加载后

第一种类型的数据,即加载您的 Web 应用所需的数据,包括 HTML、 JavaScript、CSS 以及一些图片Service Worker,以及 Cache Storage API, 提供所需的基础架构来保存这些核心资源,然后使用 以便稍后快速加载您的 Web 应用,最好是完全绕过网络。 (与 Web 应用的构建流程集成的工具,例如新的 Workbox 库或更早版本 sw-precache、 可以完全自动化地存储、更新和使用此类 data.)

但其他类型的数据呢?下载这些资源时 但它可能会对您的整体用户体验 体验例如,如果您正在编写图片编辑 Web 应用, 想要保存一张图片的一个或多个本地副本,允许用户 和撤消工作。或者,如果您要开发离线媒体 因此在本地计算机上保存音频或视频文件 功能。每个可以个性化的 Web 应用最终都需要保存一些 某种状态信息。 您如何知道有多少空间可用于此类运行时存储? 存储空间用完后会出现什么情况?

过去的时间:window.webkitStorageInfonavigator.webkitTemporaryStorage

浏览器以往通过添加前缀来支持此类自省, 例如非常旧的(和已弃用)界面 window.webkitStorageInfo、 而那些并不很久很久却仍然不标准的 navigator.webkitTemporaryStorage。 虽然这些界面能够提供有用的信息, 作为网络标准的未来趋势

这就是 WHATWG Storage Standard 存储库 进入图片。

未来:navigator.storage

随着 Storage Living Standard 的不断改进,一些实用的 API 传递给 StorageManager 该接口会以 navigator.storage。 与许多其他较新的 Web API 一样,navigator.storage 仅在安全的环境中可用 (通过 HTTPS 或 localhost 提供)。

去年,我们推出了 navigator.storage.persist() 方法,这样您的 Web 应用就可以请求 免于自动清理。

现在,通过 navigator.storage.estimate() 方法将其连接起来,该方法充当 navigator.webkitTemporaryStorage.queryUsageAndQuota() 的现代替代品。 estimate() 会返回类似的信息,但它公开 基于 promise 的接口, 与其他现代异步 API 保持一致。我们承诺 estimate() 会返回一个解析对象,该对象包含两个属性:usage 表示当前使用的字节数;quota 表示 当前可存储的字节数上限 origin。 (与存储空间相关的其他所有操作一样,配额限制在整个 origin.)

如果 Web 应用尝试使用 IndexedDB 或 Cache Storage API - 大到足以使给定源站在其上 可用配额,则该请求将失败,并显示 QuotaExceededError 异常。

实际存储空间估算值

到底如何使用 estimate() 取决于您的应用需要存储的数据类型 商店。例如,您可以在界面中更新一个控件 了解每次存储操作完成后使用了多少空间。 理想情况下,您会提供一个可让用户手动清理数据的界面 所需的资源。您可以按照以下行编写代码:

// For a primer on async/await, see
// https://developers.google.com/web/fundamentals/getting-started/primers/async-functions
async function storeDataAndUpdateUI(dataUrl) {
  // Pro-tip: The Cache Storage API is available outside of service workers!
  // See https://googlechrome.github.io/samples/service-worker/window-caches/
  const cache = await caches.open('data-cache');
  await cache.add(dataUrl);

  if ('storage' in navigator && 'estimate' in navigator.storage) {
    const {usage, quota} = await navigator.storage.estimate();
    const percentUsed = Math.round(usage / quota * 100);
    const usageInMib = Math.round(usage / (1024 * 1024));
    const quotaInMib = Math.round(quota / (1024 * 1024));

    const details = `${usageInMib} out of ${quotaInMib} MiB used (${percentUsed}%)`;

    // This assumes there's a <span id="storageEstimate"> or similar on the page.
    document.querySelector('#storageEstimate').innerText = details;
  }
}

估算值的准确性如何?

我们很难忽视这样一个事实:从函数返回的数据只是 源站占用空间的估算值。就在函数 名称!usagequota 值都不是稳定值,因此 建议您考虑以下事项:

  • usage 反映了给定来源有效使用了多少字节 同源 而这些数据又会受到内部压缩技术的影响, 固定大小的分配块(可能包含未使用的空间), 共 个“tombstone”记录 可能是在删除后临时创建的防止泄漏 包含确切尺寸信息、跨源 不透明资源 在本地存储的数据可能会对总体 usage 产生额外的填充字节 值。
  • quota 表示当前为源站预留的空间量。通过 值取决于总体存储空间大小等固定因素, 潜在易变因素的数量,包括存储空间大小 目前未使用的配置也就是说,当设备上的其他应用写入或删除 数据是指浏览器愿意为您的网络 应用的源可能会发生变化。

当前:特征检测和回退

从 Chrome 61 开始,estimate() 默认处于启用状态。Firefox 是 目前正在使用 navigator.storage 进行实验,但自 2017 年 8 月起,此功能不再开启 默认处于启用状态您需要 启用 dom.storageManager.enabled 偏好设置 以便进行测试

使用目前并非所有浏览器都支持的功能时, 特征检测是必不可少的一步。您可以将特征检测与 基于 promise 的封装容器,位于旧版 navigator.webkitTemporaryStorage 之上 方法提供一致的接口,包括:

function storageEstimateWrapper() {
  if ('storage' in navigator && 'estimate' in navigator.storage) {
    // We've got the real thing! Return its response.
    return navigator.storage.estimate();
  }

  if ('webkitTemporaryStorage' in navigator &&
      'queryUsageAndQuota' in navigator.webkitTemporaryStorage) {
    // Return a promise-based wrapper that will follow the expected interface.
    return new Promise(function(resolve, reject) {
      navigator.webkitTemporaryStorage.queryUsageAndQuota(
        function(usage, quota) {resolve({usage: usage, quota: quota})},
        reject
      );
    });
  }

  // If we can't estimate the values, return a Promise that resolves with NaN.
  return Promise.resolve({usage: NaN, quota: NaN});
}