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 e ad alte prestazioni per il web. In particolare, WebAssembly (Wasm) ha aperto le porte ad applicazioni web veloci e potenti, mentre tecnologie come Emscripten ora consentono agli sviluppatori di riutilizzare il codice collaudato sul web. Per sfruttare appieno questo potenziale, gli sviluppatori devono avere la stessa potenza e flessibilità.

È qui che entra in gioco l'API Storage Foundation. L'API Storage Foundation è una nuova API di archiviazione rapida e non pinionata che sblocca casi d'uso nuovi e molto richiesti per il web, come l'implementazione di database ad alte prestazioni e la gestione agevole 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 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à offrendo primitive generiche, semplici ed efficaci su 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 una serie di opzioni di archiviazione, ognuna delle quali è stata creata tenendo presenti casi d'uso specifici.

  • Alcune di queste opzioni chiaramente non si sovrappongono a questa proposta, in quanto consentono solo la memorizzazione di quantità molto ridotte di dati, come 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 Entries o WebSQL.
  • L'API File System Access ha una superficie API simile, ma il suo utilizzo consiste nell'interfacciarsi con il file system del client e fornire accesso a dati che potrebbero non essere di proprietà dell'origine o persino del browser. Questa diversa attenzione è data da considerazioni più rigide sulla sicurezza 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 significative limitazioni delle prestazioni. Inoltre, l'accesso diretto 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 è un tentativo 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

Ecco alcuni esempi di siti che possono utilizzare questa API:

  • App per la produttività e la creatività che funzionano su grandi quantità di dati video, audio o di immagini. Queste app possono trasferire i segmenti su disco anziché conservarli in memoria.
  • App che si basano su un file system permanente accessibile da Wasm e che necessitano di prestazioni superiori a quelle garantite da IDBFS.

Che cos'è l'API Storage Foundation?

L'API è composta da due parti principali:

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

Chiamate al 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 esistente, e altrimenti crea 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 nome 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 nuova capacità (in byte) per l'utilizzo da parte del contesto di esecuzione attuale. Restituisce una promessa che si è risolta con la quantità di capacità rimanente.
  • 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

L'utilizzo dei file avviene mediante le seguenti funzioni:

  • NativeIOFile.close(): chiude un file e restituisce una promessa che si risolve al completamento dell'operazione.
  • NativeIOFile.flush(): sincronizza (ossia fa il flush) dello 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 si risolve con la lunghezza del file in byte.
  • NativeIOFile.setLength(length): imposta la lunghezza del file in byte e restituisce una promessa che si risolve 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 i contenuti del file in un determinato offset attraverso un buffer risultante dal trasferimento del buffer specificato, che viene quindi lasciato scollegato. Restituisce un 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 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 supera la fine del file.
  • NativeIOFile.write(buffer, offset): scrive il contenuto del buffer specificato nel file in base all'offset specificato. Il buffer viene trasferito prima che i dati vengano scritti 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 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 introdotti in precedenza, 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 riprodurre la demo dell'API Storage Foundation nell'incorporamento di seguito. Crea, rinomina, scrivi e leggi i file e controlla la capacità disponibile che hai richiesto di aggiornare 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 in Controllo dell'accesso a 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. ma si limita anche a contesti sicuri.

Controllo utenti

La quota di spazio di archiviazione verrà utilizzata per distribuire l'accesso allo spazio su disco e per prevenire utilizzi illeciti. Devi prima richiedere la memoria che vuoi occupare. Come altre API di archiviazione, gli utenti possono liberare lo spazio occupato dall'API Storage Foundation tramite il proprio 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.