tl;dr
Chrome 61 将推出更多浏览器,现在可以通过以下方式提供 Web 应用当前使用了多少存储空间以及可用存储空间的估算值:
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
)可以完全自动执行存储、更新和使用此类数据的过程。)
但其他类型的数据呢?这些资源并不是加载 Web 应用的必要资源,但可能会对您的整体用户体验发挥重要作用。例如,如果您正在编写图片编辑 Web 应用,则可能需要保存图片的一个或多个本地副本,以便用户在修订版本之间切换并撤消工作。或者,如果您正在开发离线媒体播放体验,则在本地保存音频或视频文件将是一项关键功能。每个可以进行个性化设置的 Web 应用最终都需要保存某种状态信息。如何知道有多少空间可用于此类运行时存储,以及如何在空间用尽后会出现什么情况?
过去的时间:window.webkitStorageInfo
和navigator.webkitTemporaryStorage
一直以来,浏览器都是通过带前缀的接口来支持此类自省,例如非常旧的(和已废弃的)window.webkitStorageInfo
,以及不是很旧但仍非标准的 navigator.webkitTemporaryStorage
。虽然这些接口提供了有用的信息,但它们没有成为未来的 Web 标准。
这就是 WHATWG 存储标准的用武之地。
未来: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()
返回的 promise 使用包含两个属性的对象进行解析:usage
(表示当前使用的字节数)和 quota
(表示当前源站可以存储的最大字节数)。(与其他所有与存储相关的任务一样,配额将应用于整个源站。)
如果 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;
}
}
估算值的准确性如何?
您不容易错过这样一个事实:从函数返回的数据只是起点所占用空间的估算值。就在函数名称中!usage
和 quota
值都不是预期值,因此建议您考虑以下事项:
usage
反映了给定源有效用于同源数据的字节数,而这些数据又会受到内部压缩技术、可能包含未使用空间的固定大小分配块的影响,以及删除后临时创建的“tombstone”记录的存在。为了防止确切大小信息泄露,在本地保存的跨源不透明资源可能会为总体usage
值贡献额外的填充字节。quota
表示当前为源站预留的空间量。该值取决于一些常量因素(例如总体存储空间大小),但也取决于许多潜在的易变因素,包括当前未使用的存储空间量。因此,当设备上的其他应用写入或删除数据时,浏览器愿意为 Web 应用的源占用的空间量可能会发生变化。
当前:特征检测和回退
从 Chrome 61 开始,estimate()
默认处于启用状态。Firefox 正尝试使用 navigator.storage
,但自 2017 年 8 月起,此功能默认处于停用状态。您需要启用 dom.storageManager.enabled
偏好设置才能进行测试。
使用目前并非所有浏览器都支持的功能时,必须进行功能检测。您可以在旧版 navigator.webkitTemporaryStorage
方法的基础上,将功能检测与基于 promise 的封装容器相结合,以提供一致的接口,包括:
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});
}