Cómo estimar el espacio de almacenamiento disponible

Resumen

Chrome 61, al que le siguen más navegadores, ahora expone una estimación de la de almacenamiento que usa una aplicación web y cuánto está disponible mediante:

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

Apps web modernas y almacenamiento de datos

Cuando se piensa en las necesidades de almacenamiento de una aplicación web moderna, es útil dividir lo que se almacena en dos categorías: los datos principales necesarios para cargar la aplicación web y los datos necesarios para una interacción significativa del usuario una vez se cargue la aplicación.

El primer tipo de datos, los necesarios para cargar tu app web, consta de HTML. JavaScript, CSS y tal vez algunas imágenes. Service workers, además de la API de Cache Storage, proporcionar la infraestructura necesaria para guardar esos recursos centrales y, luego, usar para cargarlos con rapidez en tu app web, idealmente omitiendo por completo la red. (Las herramientas que se integran con el proceso de compilación de las aplicaciones web, como el nuevo Bibliotecas Workbox o versiones anteriores sw-precache: para automatizar completamente el proceso de almacenamiento, actualización y uso data.)

Pero ¿qué ocurre con los otros tipos de datos? Estos son recursos que no son necesarios para cargar tu app web, pero que podría tener un rol esencial una experiencia fluida a los desarrolladores. Por ejemplo, si estás escribiendo una aplicación web de edición de imágenes, puedes quieren guardar una o más copias locales de una imagen, lo que les permite a los usuarios cambiar entre revisiones y deshacer su trabajo. Si estás desarrollando un medio sin conexión experiencia de reproducción, guardar archivos de audio o video localmente sería un . Todas las aplicaciones web que se pueden personalizar terminan necesitando ahorrar algo de tipo de información de estado. ¿Cómo sabes cuánto espacio disponible para este tipo de almacenamiento en tiempo de ejecución ¿Qué pasa cuando te quedas sin espacio?

Anteriores: window.webkitStorageInfo y navigator.webkitTemporaryStorage

Históricamente, los navegadores han admitido este tipo de introspección mediante como la antigua (y obsoleta) window.webkitStorageInfo: y lo que no es tan simple, pero igual no es estándar, navigator.webkitTemporaryStorage Si bien estas interfaces proporcionaron información útil, no tienen un en el futuro como los estándares de la Web.

Para ello, el servicio estándar de almacenamiento de QUÉWG entra en la fotografía.

El futuro: navigator.storage

Como parte del trabajo continuo sobre el Storage Living Standard, un par de APIs útiles hicieron realidad en la StorageManager que se expone a los navegadores como navigator.storage. Al igual que muchas otras APIs web más recientes, navigator.storage solo está disponible en entornos seguros (entregados a través de HTTPS o localhost).

El año pasado, presentamos navigator.storage.persist() que permite a tu aplicación web solicitar que su almacenamiento se exentas de la limpieza automática.

Ahora está unida por el método navigator.storage.estimate(), que sirve como una reemplazo moderno de navigator.webkitTemporaryStorage.queryUsageAndQuota(). estimate() muestra información similar, pero expone una interfaz basada en promesas lo que concuerda con otras APIs asíncronas modernas. La promesa de que estimate() muestra resuelve con un objeto que contiene dos propiedades: usage, que representa la cantidad de bytes que se usan actualmente, y quota, que representa el la cantidad máxima de bytes que puede almacenar la red origen. Como todo lo relacionado con el almacenamiento, la cuota se aplica a todo origin.)

Si una aplicación web intenta almacenar, por ejemplo, IndexedDB o la La API de Cache Storage: datos que tienen el tamaño suficiente para transferir un origen determinado a su cuota disponible, la solicitud fallará y mostrará QuotaExceededError excepción.

Estimaciones de almacenamiento en acción

La forma exacta en la que usas estimate() depende del tipo de datos que necesite tu app para en una tienda física. Por ejemplo, puedes actualizar un control de la interfaz para que los usuarios saber cuánto espacio se usa una vez completada cada operación de almacenamiento. Lo ideal sería que proporcionarías una interfaz que les permita a los usuarios limpiar los datos manualmente. que ya no son necesarios. Puedes escribir código como los siguientes ejemplos:

// 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;
  }
}

¿Qué tan exacta es la estimación?

Es difícil pasar por alto el hecho de que los datos que obtienes de la función una estimación del espacio que usa un origen. Está justo en la función. nombre. Ni los valores usage ni quota están diseñados para ser estables, por lo que te recomendamos que tengas en cuenta lo siguiente:

  • usage refleja la cantidad de bytes que un origen determinado usa de manera efectiva para mismo origen de los datos, que a su vez pueden verse afectadas por las técnicas de compresión bloques de asignación de tamaño fijo que pueden incluir el espacio sin usar y la presencia de “tombstone” registros que se pueden crear temporalmente después de una eliminación. Para evitar la filtración de tamaño exacto, origen cruzado, recursos opacos guardados de forma local pueden aportar bytes de padding adicionales al valor general de usage valor.
  • quota refleja la cantidad de espacio reservado actualmente para un origen. El depende de factores constantes, como el tamaño total del almacenamiento, de factores potencialmente volátiles, incluida la cantidad de espacio de almacenamiento que actualmente no se usa. Así como otras aplicaciones en un dispositivo escriben o borran la cantidad de espacio que el navegador está dispuesto a dedicar a tu es probable que cambie el origen de la app.

El presente: detección de funciones y resguardos

estimate() está habilitado de forma predeterminada a partir de Chrome 61. Firefox es experimentamos con navigator.storage, pero, desde agosto de 2017, no se convirtió activado de forma predeterminada. Debes habilitar la preferencia dom.storageManager.enabled para probarlo.

Cuando se trabaja con funciones que aún no son compatibles con todos los navegadores, la detección de atributos es imprescindible. Puedes combinar la detección de atributos junto con un Wrapper basado en promesas sobre el navigator.webkitTemporaryStorage anterior para proporcionar una interfaz coherente como la siguiente:

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});
}