La plataforma web ofrece cada vez más a los desarrolladores las herramientas que necesitan para compilar aplicaciones de alto rendimiento y optimizadas para la Web. En particular, WebAssembly (Wasm) abrió las puertas a aplicaciones web rápidas y potentes, mientras que tecnologías como Emscripten ahora permiten a los desarrolladores reutilizar código probado en la Web. Para aprovechar realmente este potencial, los desarrolladores deben tener la misma potencia y flexibilidad en cuanto al almacenamiento.
Aquí es donde entra en juego la API de Storage Foundation. La API de Storage Foundation es una nueva API de almacenamiento rápida y sin opiniones que desbloquea casos de uso nuevos y muy solicitados para la Web, como implementar bases de datos de alto rendimiento y administrar archivos temporales grandes con elegancia. Con esta nueva interfaz, los desarrolladores pueden “traer su propio almacenamiento” a la Web, lo que reduce la brecha de funciones entre la Web y el código específico de la plataforma.
La API de Storage Foundation está diseñada para parecerse a un sistema de archivos muy básico, por lo que les brinda a los desarrolladores flexibilidad, ya que proporciona primitivas genéricas, simples y de alto rendimiento sobre las que pueden compilar componentes de nivel superior. Las aplicaciones pueden aprovechar la mejor herramienta para sus necesidades y encontrar el equilibrio adecuado entre usabilidad, rendimiento y confiabilidad.
¿Por qué la Web necesita otra API de almacenamiento?
La plataforma web ofrece varias opciones de almacenamiento para los desarrolladores, cada una de las cuales se compila teniendo en cuenta casos de uso específicos.
- Algunas de estas opciones claramente no se superponen con esta propuesta, ya que solo permiten almacenar cantidades muy pequeñas de datos, como las cookies o la API de Web Storage, que consta de los mecanismos
sessionStorage
ylocalStorage
. - Otras opciones ya están obsoletas por varios motivos, como la API de File and Directory Entries o WebSQL.
- La API de File System Access tiene una plataforma de API similar, pero su uso es para interactuar con el sistema de archivos del cliente y proporcionar acceso a datos que pueden estar fuera de la propiedad del origen o incluso del navegador. Este enfoque diferente conlleva consideraciones de seguridad más estrictas y costos de rendimiento más altos.
- La API de IndexedDB se puede usar como backend para algunos de los casos de uso de la API de Storage Foundation. Por ejemplo, Emscripten incluye IDBFS, un sistema de archivos persistente basado en IndexedDB. Sin embargo, como IndexedDB es, en esencia, un almacén de pares clave-valor, tiene limitaciones de rendimiento significativas. Además, acceder directamente a las subsecciones de un archivo es aún más difícil y lento en IndexedDB.
- Por último, la interfaz CacheStorage es ampliamente compatible y está ajustada para almacenar datos de gran tamaño, como recursos de aplicaciones web, pero los valores son inmutables.
La API de Storage Foundation es un intento de cerrar todas las brechas de las opciones de almacenamiento anteriores, ya que permite el almacenamiento de alto rendimiento de archivos grandes mutables definidos dentro del origen de la aplicación.
Casos de uso sugeridos para la API de Storage Foundation
Estos son algunos ejemplos de sitios que pueden usar esta API:
- Apps de productividad o creatividad que operan con grandes cantidades de datos de imágenes, audio o video Estas apps pueden descargar segmentos en el disco en lugar de mantenerlos en la memoria.
- Apps que dependen de un sistema de archivos persistente al que se puede acceder desde Wasm y que necesitan más rendimiento que el que puede garantizar IDBFS.
¿Qué es la API de Storage Foundation?
La API tiene dos partes principales:
- Llamadas al sistema de archivos, que proporcionan funcionalidad básica para interactuar con archivos y rutas de acceso a archivos.
- Controles de archivo, que proporcionan acceso de lectura y escritura a un archivo existente.
Llamadas al sistema de archivos
La API de Storage Foundation presenta un objeto nuevo, storageFoundation
, que se encuentra en el objeto window
y que incluye varias funciones:
storageFoundation.open(name)
: Abre el archivo con el nombre determinado si existe y, de lo contrario, crea uno nuevo. Muestra una promesa que se resuelve con el archivo abierto.
storageFoundation.delete(name)
: Quita el archivo con el nombre determinado. Muestra una promesa que se resuelve cuando se borra el archivo.storageFoundation.rename(oldName, newName)
: Cambia el nombre del archivo del nombre anterior al nuevo de forma atómica. Muestra una promesa que se resuelve cuando se cambia el nombre del archivo.storageFoundation.getAll()
: Muestra una promesa que se resuelve con un array de todos los nombres de archivo existentes.storageFoundation.requestCapacity(requestedCapacity)
: Solicita una nueva capacidad (en bytes) para que la use el contexto de ejecución actual. Muestra una promesa que se resolvió con el importe restante de la capacidad disponible.
storageFoundation.releaseCapacity(toBeReleasedCapacity)
: Libera la cantidad especificada de bytes del contexto de ejecución actual y muestra una promesa que se resuelve con la capacidad restante.storageFoundation.getRemainingCapacity()
: Muestra una promesa que se resuelve con la capacidad disponible para el contexto de ejecución actual.
Controles de archivos
Para trabajar con archivos, usa las siguientes funciones:
NativeIOFile.close()
: Cierra un archivo y muestra una promesa que se resuelve cuando se completa la operación.NativeIOFile.flush()
: Sincroniza (es decir, borra) el estado en la memoria de un archivo con el dispositivo de almacenamiento y muestra una promesa que se resuelve cuando se completa la operación.
NativeIOFile.getLength()
: Muestra una promesa que se resuelve con la longitud del archivo en bytes.NativeIOFile.setLength(length)
: Establece la longitud del archivo en bytes y muestra una promesa que se resuelve cuando se completa la operación. Si la longitud nueva es menor que la actual, los bytes se quitan desde el final del archivo. De lo contrario, el archivo se extiende con bytes con valor cero.NativeIOFile.read(buffer, offset)
: Lee el contenido del archivo en la compensación determinada a través de un búfer que es el resultado de transferir el búfer determinado, que luego se deja desconectado. Muestra unNativeIOReadResult
con el búfer transferido y la cantidad de bytes que se leyeron correctamente.Un
NativeIOReadResult
es un objeto que consta de dos entradas:buffer
: UnArrayBufferView
, que es el resultado de transferir el búfer pasado aread()
. Es del mismo tipo y longitud que el búfer de origen.readBytes
: Es la cantidad de bytes que se leyeron correctamente enbuffer
. Esto puede ser menor que el tamaño del búfer si se produce un error o si el rango de lectura se extiende más allá del final del archivo. Se establece en cero si el rango de lectura está más allá del final del archivo.
NativeIOFile.write(buffer, offset)
: Escribe el contenido del búfer determinado en el archivo en el desplazamiento determinado. El búfer se transfiere antes de que se escriban los datos y, por lo tanto, queda desconectado. Devuelve unNativeIOWriteResult
con el búfer transferido y la cantidad de bytes que se escribieron correctamente. El archivo se extenderá si el rango de escritura supera su longitud.Un
NativeIOWriteResult
es un objeto que consta de dos entradas:buffer
: UnArrayBufferView
que es el resultado de transferir el búfer pasado awrite()
. Es del mismo tipo y longitud que el búfer de origen.writtenBytes
: Es la cantidad de bytes que se escribieron correctamente enbuffer
. Si se produce un error, es posible que sea inferior al tamaño del búfer.
Ejemplos completos
Para que los conceptos que se presentaron anteriormente sean más claros, aquí tienes dos ejemplos completos que te guían por las diferentes etapas del ciclo de vida de los archivos de Storage Foundation.
Apertura, escritura, lectura y cierre
// Open a file (creating it if needed).
const file = await storageFoundation.open('test_file');
try {
// Request 100 bytes of capacity for this context.
await storageFoundation.requestCapacity(100);
const writeBuffer = new Uint8Array([64, 65, 66]);
// Write the buffer at offset 0. After this operation, `result.buffer`
// contains the transferred buffer and `result.writtenBytes` is 3,
// the number of bytes written. `writeBuffer` is left detached.
let result = await file.write(writeBuffer, 0);
const readBuffer = new Uint8Array(3);
// Read at offset 1. `result.buffer` contains the transferred buffer,
// `result.readBytes` is 2, the number of bytes read. `readBuffer` is left
// detached.
result = await file.read(readBuffer, 1);
// `Uint8Array(3) [65, 66, 0]`
console.log(result.buffer);
} finally {
file.close();
}
Cómo abrir, crear una lista y borrar
// Open three different files (creating them if needed).
await storageFoundation.open('sunrise');
await storageFoundation.open('noon');
await storageFoundation.open('sunset');
// List all existing files.
// `["sunset", "sunrise", "noon"]`
await storageFoundation.getAll();
// Delete one of the three files.
await storageFoundation.delete('noon');
// List all remaining existing files.
// `["sunrise", "noon"]`
await storageFoundation.getAll();
Demostración
Puedes jugar con la demo de la API de Storage Foundation en la incorporación que aparece a continuación. Crea archivos, cámbiales el nombre, escribe en ellos y léelos, y consulta la capacidad disponible que solicitaste actualizar a medida que realices cambios. Puedes encontrar el código fuente de la demostración en Glitch.
Seguridad y permisos
El equipo de Chromium diseñó e implementó la API de Storage Foundation con los principios básicos definidos en Controlling Access to Powerful Web Platform Features, incluidos el control del usuario, la transparencia y la ergonomía.
Siguiendo el mismo patrón que otras APIs de almacenamiento modernas en la Web, el acceso a la API de Storage Foundation está vinculado al origen, lo que significa que un origen solo puede acceder a los datos que se crearon. También se limita a contextos seguros.
Control de usuarios
La cuota de almacenamiento se usará para distribuir el acceso al espacio en disco y evitar abusos. Primero, se debe solicitar la memoria que deseas ocupar. Al igual que con otras APIs de almacenamiento, los usuarios pueden borrar el espacio que ocupa la API de Storage Foundation a través de su navegador.
Vínculos útiles
- Explicación pública
- Demostración de la API de Storage Foundation | Fuente de la demostración de la API de Storage Foundation
- Error de seguimiento de Chromium
- Entrada de ChromeStatus.com
- Componente Blink:
Blink>Storage>NativeIO
- Revisión de TAG
- Intención de crear prototipos
- Subproceso de WebKit
- Subproceso de Mozilla
Agradecimientos
Emanuel Krivoy y Richard Stotz especificaron e implementaron la API de Storage Foundation. Pete LePage y Joe Medley revisaron este artículo.
Imagen hero de Markus Spiske en Unsplash.