Spazio di archiviazione ad alte prestazioni per la tua app: l'API Storage Foundation

La piattaforma web offre sempre più agli sviluppatori gli strumenti necessari per creare applicazioni ottimizzate per il web ad alte prestazioni. In particolare, WebAssembly (Wasm) ha aperto le porte ad applicazioni web veloci e potenti, mentre tecnologie come Emscripten ora consentono agli sviluppatori di riutilizzare codice collaudato e testato sul web. Per sfruttare appieno questo potenziale, gli sviluppatori devono avere la stessa potenza e flessibilità in termini di archiviazione.

È qui che entra in gioco l'API Storage Foundation. L'API Storage Foundation è una nuova API di archiviazione rapida e non rigida che sblocca casi d'uso nuovi e molto richiesti per il web, come l'implementazione di database ad alte prestazioni e la gestione semplificata di file temporanei di grandi dimensioni. Con questa nuova interfaccia, gli sviluppatori possono "portare il proprio spazio di archiviazione" sul web, riducendo il divario di funzionalità tra il codice web e il codice specifico della piattaforma.

L'API Storage Foundation è progettata per assomigliare a un file system molto basilare, quindi offre agli sviluppatori flessibilità fornendo primitive generiche, semplici ed efficaci con cui possono creare componenti di livello superiore. Le applicazioni possono sfruttare lo strumento migliore per le loro esigenze, trovando il giusto equilibrio tra usabilità, prestazioni e affidabilità.

Perché il web ha bisogno di un'altra API di archiviazione?

La piattaforma web offre agli sviluppatori varie opzioni di archiviazione, ognuna delle quali è realizzata tenendo conto di casi d'uso specifici.

  • Alcune di queste opzioni chiaramente non si sovrappongono a questa proposta in quanto consentono solo l'archiviazione di quantità molto ridotte di dati, ad esempio i cookie o l'API Web Storage composta dai meccanismi sessionStorage e localStorage.
  • Altre opzioni sono già deprecate per vari motivi, ad esempio l'API File and Directory Notifications o WebSQL.
  • L'API File System Access ha una piattaforma API simile, ma viene utilizzata per interfacciarsi con il file system del client e consentire l'accesso a dati che potrebbero non appartenere all'origine o persino alla proprietà del browser. Questa attenzione diversa prevede considerazioni sulla sicurezza più rigide e costi per le prestazioni più elevati.
  • L'API IndexedDB può essere utilizzata come backend per alcuni casi d'uso dell'API Storage Foundation. Ad esempio, Emscripten include IDBFS, un file system permanente basato su IndexedDB. Tuttavia, poiché IndexedDB è fondamentalmente un archivio chiave-valore, presenta limitazioni significative delle prestazioni. Inoltre, accedere direttamente alle sottosezioni di un file è ancora più difficile e più lento in IndexedDB.
  • Infine, l'interfaccia CacheStorage è ampiamente supportata ed è ottimizzata per l'archiviazione di dati di grandi dimensioni come le risorse delle applicazioni web, ma i valori sono immutabili.

L'API Storage Foundation tenta di colmare tutte le lacune delle opzioni di archiviazione precedenti consentendo l'archiviazione ad alte prestazioni di file di grandi dimensioni modificabili definiti all'interno dell'origine dell'applicazione.

Casi d'uso suggeriti per l'API Storage Foundation

Esempi di siti che possono utilizzare questa API includono:

  • App di produttività o creatività che operano su grandi quantità di dati video, audio o immagini. Queste app possono trasferire i segmenti su disco invece di conservarli in memoria.
  • App che si basano su un file system permanente accessibile da Wasm e che richiedono prestazioni migliori rispetto a quelle che IDBFS può garantire.

Che cos'è l'API Storage Foundation?

L'API si compone di due parti principali:

  • Chiamate al file system, che offrono funzionalità di base per interagire con file e percorsi dei file.
  • Handle dei file, che forniscono l'accesso in lettura e scrittura a un file esistente.

Chiamate del file system

L'API Storage Foundation introduce un nuovo oggetto, storageFoundation, che risiede nell'oggetto window e che include una serie di funzioni:

  • storageFoundation.open(name): apre il file con il nome specificato se esiste e crea in altro modo un nuovo file. Restituisce una promessa che si risolve con il file aperto.
  • storageFoundation.delete(name): rimuove il file con il nome specificato. Restituisce una promessa che si risolve quando il file viene eliminato.
  • storageFoundation.rename(oldName, newName): rinomina il file dal vecchio nome al nuovo a livello atomico. Restituisce una promessa che si risolve quando il file viene rinominato.
  • storageFoundation.getAll(): restituisce una promessa che si risolve con un array di tutti i nomi file esistenti.
  • storageFoundation.requestCapacity(requestedCapacity): richiede una nuova capacità (in byte) per l'utilizzo da parte del contesto di esecuzione attuale. Restituisce una promessa che si è risolta con la quantità rimanente di capacità disponibile.
  • storageFoundation.releaseCapacity(toBeReleasedCapacity): rilascia il numero specificato di byte dal contesto di esecuzione attuale e restituisce una promessa che si risolve con la capacità rimanente.
  • storageFoundation.getRemainingCapacity(): restituisce una promessa che si risolve con la capacità disponibile per il contesto di esecuzione attuale.

Handle dei file

La gestione dei file avviene tramite le seguenti funzioni:

  • NativeIOFile.close(): chiude un file e restituisce una promessa che si risolve al completamento dell'operazione.
  • NativeIOFile.flush(): sincronizza (ovvero, svuota) lo stato in memoria di un file con il dispositivo di archiviazione e restituisce una promessa che si risolve al completamento dell'operazione.
  • NativeIOFile.getLength(): restituisce una promessa che viene risolta con la lunghezza del file in byte.
  • NativeIOFile.setLength(length): imposta la lunghezza del file in byte e restituisce una promessa che viene risolta al completamento dell'operazione. Se la nuova lunghezza è inferiore a quella attuale, i byte vengono rimossi a partire dalla fine del file. In caso contrario, il file viene esteso con byte a valore zero.
  • NativeIOFile.read(buffer, offset): legge il contenuto del file nell'offset specificato tramite un buffer risultante dal trasferimento del buffer specificato, che viene poi scollegato. Restituisce un valore NativeIOReadResult con il buffer trasferito e il numero di byte letti correttamente.

    Un NativeIOReadResult è un oggetto composto da due voci:

    • buffer: un elemento ArrayBufferView, il risultato del trasferimento del buffer passato a read(). È dello stesso tipo e della stessa lunghezza del buffer di origine.
    • readBytes: il numero di byte letti correttamente in buffer. Potrebbe essere inferiore alla dimensione del buffer, se si verifica un errore o se l'intervallo di lettura supera la fine del file. È impostato su zero se l'intervallo di lettura è oltre la fine del file.
  • NativeIOFile.write(buffer, offset): scrive i contenuti del buffer specificato nel file all'offset specificato. Il buffer viene trasferito prima della scrittura dei dati e viene quindi lasciato scollegato. Restituisce un valore NativeIOWriteResult con il buffer trasferito e il numero di byte scritti correttamente. Il file verrà esteso se l'intervallo di scrittura supera la sua lunghezza.

    Un NativeIOWriteResult è un oggetto composto da due voci:

    • buffer: un elemento ArrayBufferView che è il risultato del trasferimento del buffer passato a write(). È dello stesso tipo e della stessa lunghezza del buffer di origine.
    • writtenBytes: il numero di byte scritti correttamente in buffer. In caso di errore, potrebbe essere inferiore alla dimensione del buffer.

Esempi completi

Per rendere più chiari i concetti presentati sopra, ecco due esempi completi che illustrano le diverse fasi del ciclo di vita dei file di Storage Foundation.

Apertura, scrittura, lettura, chiusura

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

Apertura, scheda, eliminazione

// 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();

Demo

Puoi guardare la demo dell'API Storage Foundation nell'incorporamento seguente. Puoi creare, rinominare, scrivere e leggere dai file e controllare la capacità disponibile per cui hai richiesto l'aggiornamento man mano che apporti modifiche. Puoi trovare il codice sorgente della demo su Glitch.

Sicurezza e autorizzazioni

Il team di Chromium ha progettato e implementato l'API Storage Foundation utilizzando i principi fondamentali definiti nella sezione Controllo dell'accesso alle funzionalità avanzate della piattaforma web, tra cui controllo degli utenti, trasparenza ed ergonomia.

Seguendo lo stesso pattern di altre API di archiviazione moderne sul web, l'accesso all'API Storage Foundation è legato all'origine, il che significa che un'origine può accedere solo ai dati creati autonomamente. Inoltre, è limitata a contesti sicuri.

Controllo utente

La quota di archiviazione verrà utilizzata per distribuire l'accesso allo spazio su disco e per impedire utilizzi illeciti. La memoria che vuoi occupare deve prima essere richiesta. Come altre API di archiviazione, gli utenti possono liberare lo spazio occupato dall'API Storage Foundation tramite il browser.

Link utili

Ringraziamenti

L'API Storage Foundation è stata specificata e implementata da Emanuel Krivoy e Richard Stotz. Questo articolo è stato esaminato da Pete LePage e Joe Medley.

Immagine hero tramite Markus Spiske su Unsplash.