KV Storage: il primo modulo integrato del Web

I fornitori di browser e gli esperti di prestazioni web sostengono da gran parte dell'ultimo decennio che localStorage è lento e che gli sviluppatori web dovrebbero smettere di utilizzarlo.

A dire il vero, chi lo dice non sbaglia. localStorage è un'API sincrona che blocca il thread principale e ogni volta che accedi potenzialmente impedisci alla tua pagina di essere interattiva.

Il problema è che l'API localStorage è così semplice e allettante e l'unica alternativa asincrona a localStorage è IndexedDB, che (ammettiamolo) non è nota per la sua facilità d'uso o per la sua API intuitiva.

Pertanto, gli sviluppatori devono scegliere tra un'opzione difficile da utilizzare e un'altra che influisce negativamente sulle prestazioni. Sebbene esistano librerie che offrono la semplicità dell'API localStorage, ma che in realtà utilizzano API di archiviazione asincrone sotto il cofano, l'inclusione di una di queste librerie nella tua app ha un costo in termini di dimensioni del file e può incidere sul tuo budget di prestazioni.

Ma cosa succederebbe se fosse possibile ottenere le prestazioni di un'API di archiviazione asincrona con la semplicità dell'API localStorage, senza dover pagare il costo delle dimensioni del file?

Beh, a breve potrebbe essere disponibile. Chrome sta sperimentando una nuova funzionalità nota come moduli integrati e il primo che prevediamo di rilasciare è un modulo di archiviazione chiave/valore asincrono chiamato KV Storage.

Prima di entrare nei dettagli del modulo di archiviazione KV, lascia che ti spieghi cosa intendo per moduli integrati.

Che cosa sono i moduli integrati?

I moduli integrati sono come i normali moduli JavaScript, solo che non devono essere scaricati perché sono forniti con il browser.

Come le API web tradizionali, i moduli integrati devono seguire un processo di standardizzazione: ognuno avrà una propria specifica che richiede una revisione del design e indicazioni positive di supporto sia da parte degli sviluppatori web che di altri fornitori di browser prima di poter essere implementato. In Chrome, i moduli integrati seguiranno la stessa procedura di lancio che utilizziamo per implementare e rilasciare tutte le nuove API.

A differenza delle API web tradizionali, i moduli integrati non sono esposti nell'ambito globale, ma sono disponibili solo tramite importazioni.

La mancata esposizione dei moduli integrati a livello globale presenta molti vantaggi: non aggiungeranno alcun overhead all'avvio di un nuovo contesto di runtime JavaScript (ad es. una nuova scheda, un worker o un worker di servizio) e non consumeranno memoria o CPU, a meno che non vengano effettivamente importati. Inoltre, non corrono il rischio di collisioni di nomi con altre variabili definite nel codice.

Per importare un modulo integrato, utilizza il prefisso std: seguito dall'identificatore del modulo integrato. Ad esempio, nei browser supportati, puoi importare il modulo KV Storage con il seguente codice (vedi di seguito come utilizzare un polyfill KV Storage nei browser non supportati):

import storage, {StorageArea} from 'std:kv-storage';

Il modulo di archiviazione KV

Il modulo KV Storage è simile per semplicità all'API localStorage, ma la sua forma è in realtà più simile a un Map JavaScript. Invece di getItem(), setItem(), e removeItem(), sono presenti get(), set(), e delete(). Dispone inoltre di altri metodi simili a map non disponibili per localStorage, come keys(), values() e entries(), e, come per Map, le relative chiavi non devono essere stringhe. Possono essere di qualsiasi tipo serializzabile strutturato.

A differenza di Map, tutti i metodi di archiviazione KV restituiscono promise o iteratori asincroni (poiché il punto principale di questo modulo è che non è sincrono, al contrario di localStorage). Per visualizzare l'API completa in dettaglio, puoi consultare la specifica.

Come potresti aver notato dall'esempio di codice riportato sopra, il modulo KV Storage ha un'esportazione predefinita storage e un'esportazione denominata StorageArea.

storage è un'istanza della classe StorageArea con il nome 'default' e sarà utilizzata più spesso dagli sviluppatori nel codice dell'applicazione. La classe StorageArea viene fornita per i casi in cui è necessario un isolamento aggiuntivo (ad es. una libreria di terze parti che memorizza i dati e vuole evitare conflitti con i dati archiviati tramite l'istanza storage predefinita). I dati di StorageArea vengono archiviati in un database IndexedDB con il nome kv-storage:${name}, dove name è il nome dell'istanza StorageArea.

Ecco un esempio di come utilizzare il modulo di archiviazione KV nel codice:

import storage from 'std:kv-storage';

const main = async () => {
  const oldPreferences = await storage.get('preferences');

  document.querySelector('form').addEventListener('submit', async () => {
    const newPreferences = Object.assign({}, oldPreferences, {
      // Updated preferences go here...
    });

    await storage.set('preferences', newPreferences);
  });
};

main();

Cosa succede se un browser non supporta un modulo integrato?

Se hai dimestichezza con l'utilizzo di moduli JavaScript nativi nei browser, probabilmente sai che (almeno finora) l'importazione di qualsiasi elemento diverso da un URL genererà un errore. Inoltre, std:kv-storage non è un URL valido.

Da qui sorge la domanda: dobbiamo attendere che tutti i browser supportino i moduli integrati prima di poterli utilizzare nel nostro codice? Fortunatamente, la risposta è no.

Puoi utilizzare i moduli integrati non appena anche un browser li supporta grazie all'aiuto di un'altra funzionalità su cui stiamo sperimentando chiamata importa mappe.

Importare le mappe

Le mappe di importazione sono essenzialmente un meccanismo tramite il quale gli sviluppatori possono assegnare un alias agli identificatori di importazione a uno o più identificatori alternativi.

Questa funzionalità è molto utile perché ti consente di modificare (in fase di esecuzione) il modo in cui un browser risolve un determinato identificatore di importazione nell'intera applicazione.

Nel caso dei moduli integrati, puoi fare riferimento a un polyfill del modulo nel codice dell'applicazione, ma un browser che supporta il modulo integrato può caricare quella versione.

Ecco come dichiarare una mappa di importazione per far funzionare questa operazione con il modulo KV Storage:

<!-- The import map is inlined into your page -->
<script type="importmap">
{
  "imports": {
    "/path/to/kv-storage-polyfill.mjs": [
      "std:kv-storage",
      "/path/to/kv-storage-polyfill.mjs"
    ]
  }
}
</script>

<!-- Then any module scripts with import statements use the above map -->
<script type="module">
  import storage from '/path/to/kv-storage-polyfill.mjs';

  // Use `storage` ...
</script>

Il punto chiave del codice riportato sopra è che l'URL /path/to/kv-storage-polyfill.mjs viene mappato a due risorse diverse: std:kv-storage e poi di nuovo l'URL originale, /path/to/kv-storage-polyfill.mjs.

Pertanto, quando il browser rileva un'istruzione di importazione che fa riferimento a quell'URL (/path/to/kv-storage-polyfill.mjs), prima tenta di caricare std:kv-storage, e se non ci riesce, passa al caricamento /path/to/kv-storage-polyfill.mjs.

Ancora una volta, la magia è che il browser non deve supportare le mappe di importazione o i moduli integrati per il funzionamento di questa tecnica, poiché l'URL passato al statement di importazione è l'URL del polyfill. Il polyfill non è un valore di riserva, è l'impostazione predefinita. Il modulo integrato è un miglioramento progressivo.

Che dire dei browser che non supportano affatto i moduli?

Per utilizzare le mappe di importazione per caricare condizionatamente i moduli integrati, devi effettivamente utilizzare le istruzioni import, il che significa anche che devi utilizzare gli script del modulo, ovvero <script type="module">.

Attualmente, più dell'80% dei browser supporta i moduli e, per i browser che non lo fanno, puoi utilizzare la tecnica module/nomodule per pubblicare un bundle precedente. Tieni presente che, quando generi la compilazionenomodule, devi includere tutti i polyfill perché sai con certezza che i browser che non supportano i moduli non supporteranno sicuramente i moduli integrati.

Demo di KV Storage

Per dimostrare che è possibile utilizzare i moduli integrati continuando a supportare i browser meno recenti, ho creato una demo che incorpora tutte le tecniche descritte sopra ed è attualmente eseguibile in tutti i browser:

  • I browser che supportano i moduli, le mappe di importazione e il modulo integrato non caricano codice non necessario.
  • I browser che supportano i moduli e le mappe di importazione, ma non il modulo integrato, caricano il polyfill di KV Storage (tramite il caricatore di moduli del browser).
  • I browser che supportano i moduli, ma non le mappe di importazione, caricano anche il polyfill KV Storage (tramite il caricatore di moduli del browser).
  • I browser che non supportano affatto i moduli ricevono il polyfill KV Storage nel loro bundle precedente (caricato tramite <script nomodule>).

La demo è ospitata su Glitch, quindi puoi visualizzarne il codice sorgente. Puoi trovare una spiegazione dettagliata dell'implementazione anche nel README. Dai un'occhiata se vuoi scoprire come è stato creato.

Per vedere effettivamente il modulo nativo integrato in azione, devi caricare la demo in Chrome 74 o versioni successive con il flag delle funzionalità della piattaforma web sperimentale attivato (chrome://flags/#enable-experimental-web-platform-features).

Puoi verificare che il modulo integrato venga caricato perché non vedrai lo script polyfill nel riquadro di origine di DevTools, ma vedrai la versione del modulo integrato (curiosità: puoi effettivamente ispezionare il codice sorgente del modulo o persino inserire breakpoint):

Il codice sorgente del modulo di archiviazione KV in Chrome DevTools

Inviaci un feedback

Questa introduzione dovrebbe averti dato un'idea di cosa sia possibile fare con i moduli integrati. E spero che tu sia entusiasta. Ci farebbe molto piacere se gli sviluppatori provassero il modulo KV Storage (nonché tutte le nuove funzionalità discusse qui) e ci inviassero un feedback.

Ecco i link a GitHub dove puoi inviarci un feedback per ciascuna delle funzionalità menzionate in questo articolo:

Se al momento il tuo sito utilizza localStorage, ti consigliamo di provare a passare all'API KV Storage per verificare se soddisfa tutte le tue esigenze. Se ti registri alla prova dell'origine di archiviazione KV, puoi implementare queste funzionalità oggi stesso. Tutti gli utenti dovrebbero trarre vantaggio da un miglioramento delle prestazioni dello spazio di archiviazione e gli utenti di Chrome 74 e versioni successive non dovranno pagare alcun costo aggiuntivo per i download.