Gli oggetti web storage localStorage e sessionStorage permetto di salvare le coppie key/value nel browser. Ci che interessante che i dati rimangono memorizzati anche in seguito al ricaricamento della pagina (per sessionStorage) e anche in seguito a un riavvio del browser (per localStorage). Vedremo come.
Abbiamo gi a disposizione i cookies. Perch usare altri oggetti?
- Rispetto ai cookies, gli oggetti web storage non vengono inviati al server con ogni richiesta. Per questo motivo, possiamo archiviarne molti di pi. La maggior parte dei browser permette almeno 2 megabytes di dati (o pi) e possiedono impostazioni per configurare questa scelta.
- Inoltre, il server non pu manipolare la memorizzazione degli oggetti tramite HTTP headers. Tutto viene fatto in JavaScript.
- Larchiviazione legata alla sorgete (origin) (domain/protocol/port triplet). Questo perch, protocolli differenti o sotto domini deducono diverse archiviazioni a oggetti e non possono accedere ai dati tra di loro.
Le due archiviazioni a oggetti propongono stessi metodi e propriet:
setItem(key, value): memorizza la coppia key/value.getItem(key): lettura del valore dalla key.removeItem(key): rimuove la key, ed il relativo value.clear(): rimuove tutti gli elementi.key(index): lettura della key allindiceindex.length: il numero di oggetti archiviati.
Come potete vedere, simile alla collezione Map (setItem/getItem/removeItem), mantiene comunque lordine degli elementi e permette il loro accesso tramite indice con key(index).
Vediamo come funziona.
localStorage demo
Le caratteristiche principali di localStorage sono:
- Condivisione tra le tabs e finestre provenienti dalla stessa origine.
- I dati non scadono. Rimangono in seguito a un riavvio del browser o dellintero sistema operativo.
Per esempio, il seguente esempio:
localStorage.setItem('test', 1);
E chiudiamo/apriamo il browser o semplicemente apriamo la stessa pagina in una finestra diversa, possiamo ottenere il risultato atteso in questo modo:
alert( localStorage.getItem('test') ); // 1
Dobbiamo solo essere nello stesso punto di partenza (domain/port/protocol), lURL di destinazione pu essere differente.
Il localStorage condiviso tra tutte le finestre con la stessa provenienza, quindi se impostiamo i dati in una finestra, il cambiamento diventa visibile anche nelle altre schede.
Accesso in stile oggetto
Possiamo usare la stessa sintassi di lettura/scrittura degli oggetti per accedere agli elementi, in questo modo:
// imposta un nuovo valore
localStorage.test = 2;
// legge il valore
alert( localStorage.test ); // 2
// rimuove il valore
delete localStorage.test;
Questo permesso per ragioni storiche, e principalmente funziona, ma generalmente non raccomandato, perch:
-
Se la key generata dallutente, pu essere qualsiasi cosa, come
lengthotoString, o un altro metodo integrato dilocalStorage. In questo casogetItem/setItemfunziona normalmente, mentre laccesso in stile oggetto non funziona:let key = 'length'; localStorage[key] = 5; // Error, can't assign length -
C un evento
storage, che viene emesso quando modifichiamo dati. Questo evento viene per gli accessi in stile oggetto. Vedremo pi avanti nel capitolo.
Cicli sulle keys
Come abbiamo visto, i metodi forniscono funzionalit get/set/remove. Ma come otteniamo tutti i valori o keys salvate?
Sfortunatamente, gli oggetti archiviati non sono iterabili.
Una soluzione sarebbe quella di eseguire un loop su di loro come un array:
for(let i=0; i<localStorage.length; i++) {
let key = localStorage.key(i);
alert(`${key}: ${localStorage.getItem(key)}`);
}
Un altro modo quello di usare un loop for key in localStorage , come facciamo con oggetti regolari.
Literazione avverr sulle keys, ma anche sugli outputs di campi associati ad alcune funzioni built-in di cui non abbiamo bisogno:
// cattivo esempio
for(let key in localStorage) {
alert(key); // mostra getItem, setItem e altre funzioni integrate
}
dunque dobbiamo filtrare i campi dal prototype con il controllo hasOwnProperty:
for(let key in localStorage) {
if (!localStorage.hasOwnProperty(key)) {
continue; // salta keys come "setItem", "getItem" etc
}
alert(`${key}: ${localStorage.getItem(key)}`);
}
oppure possiamo ottenere le keys proprie con Object.keys ed eseguire il loop su di loro se necessario:
let keys = Object.keys(localStorage);
for(let key of keys) {
alert(`${key}: ${localStorage.getItem(key)}`);
}
Un lavoro extra, poich Object.keys restituisce solo le keys che appartengono all oggetto, ignorando il prototype.
Solo stringhe
Da notare che sia key che i value devono essere stringhe.
Se ci fosse un altro tipo di dato, come un numero, o un object, verrebbe automaticamente convertito a stringa:
localStorage.user = {name: "John"};
alert(localStorage.user); // [object Object]
Possiamo usare JSON per archiviare oggetti:
localStorage.user = JSON.stringify({name: "John"});
// successivamente
let user = JSON.parse( localStorage.user );
alert( user.name ); // John
Inoltre possibile convertire a stringa lintero archivio di oggetti, per esempio per motivi di debugging:
// aggiunte le opzioni di formattazione a JSON.stringify per rendere object migliore
alert( JSON.stringify(localStorage, null, 2) );
sessionStorage
Loggetto sessionStorage usato molto meno spesso del localStorage.
Propriet e metodi sono gli stessi, ma pi limitato:
- La
sessionStorageesiste solo allintero della tab del browser corrente.- Unaltra tab con la stessa pagina avr un archiviazione differente.
- Viene comunque condivisa tra iframes nella stessa tab (assumendo che la loro provenienza sia la stessa).
- I dati sopravvivono al refresh della pagina, ma non alla chiusura/apertura della tab.
Vediamo come si comporta.
Esegui questo codice
sessionStorage.setItem('test', 1);
Poi ricarica la pagina. Pra potrai comunque ottenere i dati:
alert( sessionStorage.getItem('test') ); // dopo il refresh: 1
Ma se apri la stessa pagina in unaltra tab, e provi di nuovo, dal codice otterrai null, ovvero non stato trovato nulla.
Questo perch sessionStorage legato non solo allorigine, ma anche alla tab del browser. Per questo motivo, sessionStorage usato sporadicamente.
Evento di storage
Quando i dati vengono aggiornati in localStorage o sessionStorage, un evento di storage viene emesso, con le seguenti propriet:
key: La key che stata modificata (nullse stato invocato.clear()).oldValue: Il vecchio valore (nullse la chiave nuova).newValue: il nuovo valore (nullse la chiave sta rimossa).URL: LURL del documento in cui avvenuto laggiornamento.storageArea: se laggiornamento avvenuto inlocalStorageosessionStorage.
La cosa importante : levento si attiva in tutti gli oggetti window dove larchivio accessibile, ad eccezione per quello in cui stato causato.
Elaboriamo.
Immaginate di avere due finestre aperte con lo stesso sito allinterno. Quindi localStorage condiviso tra le due.
Dovresti aprire questa pagina in due browser per testare il seguente codice.
Se entrambe le finestre sono connesse a window.onstorage, allora reagiranno agli aggiornamenti che accadono in una delle due.
// attiva un aggiornamento fatto dallo stesso archivio degli altri documenti
window.onstorage = event => { // identico a window.addEventListener('storage', event => {
if (event.key != 'now') return;
alert(event.key + ':' + event.newValue + " at " + event.URL);
};
localStorage.setItem('now', Date.now());
Notare che levento contiene: event.URL lURL del documento in cui i dati sono stati aggiornati.
Inoltre, event.storageArea contiene lo storage object levento lo stesso per entrambi sessionStorage e localStorage, quindi event.storageArea si rivolge a quello che stato modificato. Potremmo anche impostare qualcosa allinterno, per rispondere al cambiamento.
That allows different windows from the same origin to exchange messages.
I browser moderni supportano Broadcast channel API, un API speciale per comunicazione inter-finestra provenienti dalla stessa sorgente, possiede molte pi funzionalit ma meno supportata. Esistono librerie che sostituiscono quella API, basate su localStorage, che lo rendono disponibile ovunque.
Riepilogo
Gli oggetti web storage localStorage e sessionStorage permettono di archiviare key/value nel browser.
- Sia
keyevaluedevono essere stringhe. - Il limite 2mb+, dipende dal browser.
- Non scadono.
- I dati sono legati alla sorgente (domain/port/protocol).
localStorage |
sessionStorage |
|---|---|
| Condivise tra tutte le tabs e finestre provenienti dalla stessa sorgente | Visibile allinterno di una tab del browser, incluso iframes della stessa origine |
| Sopravvivono al riavvio del browser | Sopravvivono al refresh della pagina (ma non alla chiusura della tab) |
API:
setItem(key, value): archivia coppia key/value .getItem(key): legge il valore dalla chiave.removeItem(key): rimuove la chiave con il suo valore.clear(): cancella tutto.key(index): legge il valore allindiceindex.length: il numero di oggetti archiviati.- Utilizza
Object.keysper ottenere tutte le chiavi. - Accediamo alle keys come propriet degli oggetti, in questo caso levento
storagenon verr emesso.
Evento di storage:
- Emesso su chiamata di
setItem,removeItem,clear. - Contiene tutti i data riguardo loperazione (
key/oldValue/newValue), il documentoURLe lo storage objectstorageArea. - Emesso su tutti gli oggetti
windowche hanno accesso allarchivio eccetto quello da cui stato generato (allinterno di una tab persessionStorage, globalmente perlocalStorage).
Commenti
<code>, per molte righe includile nel tag<pre>, per pi di 10 righe utilizza una sandbox (plnkr, jsbin, codepen)