Webové ukládacà objekty localStorage a sessionStorage umožÅujà ukládat v prohlÞeÄi dvojice klÃÄ/hodnota.
ZajÃmavé na nich je to, že data pÅežijà znovunaÄtenà stránky (u sessionStorage) a dokonce kompletnà restart prohlÞeÄe (u localStorage). Velmi brzy to uvidÃme.
K Äemu jsou dalšà objekty, když už máme cookies?
- Na rozdÃl od cookies nejsou webové ukládacà objekty s každým požadavkem odesÃlány na server. Z toho důvodu do nich můžeme uložit mnohem vÃce dat. VÄtÅ¡ina modernÃch prohlÞeÄů dovoluje nejménÄ 5 megabytů dat (nebo vÃce) a umožÅuje to konfigurovat ve svých nastavenÃch.
- RovnÄž na rozdÃl od cookies nemůže server manipulovat s ukládacÃmi objekty pomocà HTTP hlaviÄek. VÅ¡echno se provádà v JavaScriptu.
- ÃložiÅ¡tÄ je vázáno na původ (trojice doména/protokol/port). To znamená, že různé protokoly nebo subdomény vytváÅejà různé ukládacà objekty a nemohou vzájemnÄ pÅistupovat ke svým datům.
Oba ukládacà objekty poskytujà stejné metody a vlastnosti:
setItem(klÃÄ, hodnota)â uložà dvojici klÃÄ/hodnota.getItem(klÃÄ)â vrátà hodnotu podle klÃÄe.removeItem(klÃÄ)â odstranà klÃÄ s jeho hodnotou.clear()â vymaže vÅ¡e.key(index)â vrátà klÃÄ na zadané pozici.lengthâ poÄet uložených dvojic.
Jak vidÃte, podobajà se kolekci Map (setItem/getItem/removeItem), ale navÃc umožÅujà pÅÃstup podle indexu metodou key(index).
PodÃvejme se, jak to funguje.
Demo pro localStorage
Hlavnà vlastnosti localStorage jsou:
- Je sdÃlen mezi vÅ¡emi záložkami a okny stejného původu.
- Data neexpirujÃ. Zůstanou uložena po restartu prohlÞeÄe a dokonce i po restartu operaÄnÃho systému.
Když si napÅÃklad spustÃte tento kódâ¦
localStorage.setItem('test', 1);
â¦a zavÅete a pak otevÅete prohlÞeÄ nebo jen otevÅete stejnou stránku v jiném oknÄ, můžete zÃskat uložená data takto:
alert( localStorage.getItem('test') ); // 1
MusÃme jen být na stejném původu (doména/protokol/port), URL cesta se může liÅ¡it.
Objekt localStorage sdÃlejà vÅ¡echna okna se stejným původem, takže pokud nastavÃme data v jednom oknÄ, zmÄna bude viditelná i v ostatnÃch.
Objektový pÅÃstup
NaÄÃtat a ukládat klÃÄe můžeme i ÄistÄ objektovým pÅÃstupem, napÅÃklad:
// uloženà klÃÄe
localStorage.test = 2;
// naÄtenà klÃÄe
alert( localStorage.test ); // 2
// odstranÄnà klÃÄe
delete localStorage.test;
Z historických důvodů je to dovoleno a vÄtÅ¡inou to funguje, ale obecnÄ se to nedoporuÄuje, protože:
-
Jestliže je klÃÄ generován uživatelem, může jÃm být cokoli, napÅ.
length,toStringnebo název jiné zabudované metodylocalStorage. V takovém pÅÃpadÄgetItem/setItemfungujà dobÅe, ale objektový pÅÃstup selže:let klÃÄ = 'length'; localStorage[klÃÄ] = 5; // Chyba, nelze nastavit vlastnost length -
Existuje událost
storage, která se spustà pÅi zmÄnÄ dat. PÅi objektovém pÅÃstupu se tato událost nespustÃ. UvidÃme to pozdÄji v této kapitole.
Cyklus nad klÃÄi
Jak jsme vidÄli, tyto metody poskytujà funkcionalitu ânaÄti/ulož/odstraÅ klÃÄâ. Ale jak zÃskat vÅ¡echny uložené hodnoty nebo klÃÄe?
NaneÅ¡tÄstà ukládacà objekty nejsou iterovatelné.
JednÃm způsobem je procházet je v cyklu jako pole:
for(let i=0; i<localStorage.length; i++) {
let klÃÄ = localStorage.key(i);
alert(`${klÃÄ}: ${localStorage.getItem(klÃÄ)}`);
}
DalÅ¡Ãm způsobem je použÃt cyklus for klÃÄ in localStorage, stejnÄ jako u bÄžných objektů.
Ten iteruje nad klÃÄi, ale také vypÃÅ¡e nÄkolik zabudovaných polÃ, která nepotÅebujeme:
// špatný pokus
for(let klÃÄ in localStorage) {
alert(klÃÄ); // zobrazà getItem, setItem a jiné zabudované vÄci
}
â¦MusÃme tedy buÄ odfiltrovat pole z prototypu kontrolou hasOwnProperty:
for(let klÃÄ in localStorage) {
if (!localStorage.hasOwnProperty(klÃÄ)) {
continue; // pÅeskakuje klÃÄe jako "setItem", "getItem" atd.
}
alert(`${klÃÄ}: ${localStorage.getItem(klÃÄ)}`);
}
â¦Nebo prostÄ naÄÃst âvlastnÃâ klÃÄe pomocà Object.keys a pak nad nimi spustit cyklus, je-li to zapotÅebÃ:
let klÃÄe = Object.keys(localStorage);
for(let klÃÄ of klÃÄe) {
alert(`${klÃÄ}: ${localStorage.getItem(klÃÄ)}`);
}
To funguje, protože Object.keys vrátà jen klÃÄe, které náležà objektu, a ignoruje prototyp.
Pouze ÅetÄzce
ProsÃme vÅ¡imnÄte si, že klÃÄ i hodnota musejà být ÅetÄzce.
Pokud jsou jiného typu, napÅÃklad ÄÃslo nebo objekt, budou automaticky pÅevedeny na ÅetÄzec:
localStorage.uživatel = {jméno: "Jan"};
alert(localStorage.uživatel); // [object Object]
Můžeme ovÅ¡em k ukládánà objektů použÃt JSON:
localStorage.uživatel = JSON.stringify({jméno: "Jan"});
// o nÄco pozdÄji
let uživatel = JSON.parse( localStorage.uživatel );
alert( uživatel.jméno ); // Jan
Je také možné pÅevést na ÅetÄzec celý ukládacà objekt, napÅ. pro úÄely ladÄnÃ:
// do JSON.stringify pÅidáme formátovacà možnosti, aby objekt vypadal lépe
alert( JSON.stringify(localStorage, null, 2) );
sessionStorage
Objekt sessionStorage se použÃvá výraznÄ ménÄ Äasto než localStorage.
Jeho vlastnosti a metody jsou stejné, ale objekt je mnohem omezenÄjÅ¡Ã:
- Objekt
sessionStorageexistuje jedinÄ uvnitÅ aktuálnà záložky prohlÞeÄe.- Dalšà záložka se stejnou stránkou bude mÃt jiné úložiÅ¡tÄ.
- Objekt je vÅ¡ak sdÃlen mezi vnitÅnÃmi rámy ve stejné záložce (za pÅedpokladu, že pocházejà ze stejného původu).
- Data pÅežijà znovunaÄtenà stránky, ale ne zavÅenà a otevÅenà záložky.
PodÃvejme se na to v akci.
SpusÅ¥te si tento kódâ¦
sessionStorage.setItem('test', 1);
â¦Pak aktualizujte stránku. Nynà stále můžete zÃskat data:
alert( sessionStorage.getItem('test') ); // po aktualizaci: 1
â¦Ale pokud si otevÅete tutéž stránku v jiné záložce a zkusÃte to znovu tam, uvedený kód vrátà null, což znamená ânic nenalezenoâ.
Je to proto, že sessionStorage je vázán nejen na původ, ale i na záložku prohlÞeÄe. Z toho důvodu se sessionStorage použÃvá zÅÃdkakdy.
Událost storage
Když jsou data v localStorage nebo sessionStorage zmÄnÄna, spustà se událost storage s následujÃcÃmi vlastnostmi:
keyâ klÃÄ, který byl zmÄnÄn (null, pokud bylo voláno.clear()).oldValueâ původnà hodnota (null, pokud byl pÅidán nový klÃÄ).newValueâ nová hodnota (null, pokud byl klÃÄ odstranÄn).urlâ URL dokumentu, na nÄmž ke zmÄnÄ doÅ¡lo.storageAreaâ objektlocalStoragenebosessionStorage, v nÄmž ke zmÄnÄ doÅ¡lo.
Důležité je, že tato událost se spustà na vÅ¡ech objektech window, v nichž je úložiÅ¡tÄ dostupné, kromÄ toho, který ji způsobil.
VysvÄtlÃme to.
PÅedstavte si, že máte dvÄ okna a v obou je stejné sÃdlo. Objekt localStorage je tedy sdÃlen obÄma.
Možná budete chtÃt otevÅÃt si tuto stránku ve dvou oknech prohlÞeÄe, abyste otestovali následujÃcà kód.
Jestliže obÄ okna naslouchajà window.onstorage, pak každé bude reagovat na zmÄny, ke kterým doÅ¡lo ve druhém oknÄ.
// spustà se pÅi zmÄnách, které byly uÄinÄny ve stejném úložiÅ¡ti z jiných dokumentů
window.onstorage = událost => { // můžeme použÃt i window.addEventListener('storage', událost => {
if (událost.key != 'nynÃ') return;
alert(událost.key + ':' + událost.newValue + " na " + událost.url);
};
localStorage.setItem('nynÃ', Date.now());
ProsÃme vÅ¡imnÄte si, že událost také obsahuje událost.url â URL dokumentu, v nÄmž byla data zmÄnÄna.
NavÃc událost.storageArea obsahuje ukládacà objekt â tato událost je stejná pro sessionStorage i pro localStorage, takže událost.storageArea se odkazuje na objekt, který byl zmÄnÄn. Můžeme v nÄm dokonce chtÃt nÄco nastavit, abychom na zmÄnu âodpovÄdÄliâ.
To umožÅuje různým oknům stejného původu vymÄÅovat si zprávy.
Modernà prohlÞeÄe podporujà také Broadcast Channel API, speciálnà API pro komunikaci mezi okny stejného původu. Má vÃce schopnostÃ, ale je ménÄ podporováno. Existujà knihovny, které provádÄjà polyfill tohoto API založený na localStorage, dÃky nÄmuž je dostupné vÅ¡ude.
ShrnutÃ
Webové ukládacà objekty localStorage a sessionStorage umožÅujà v prohlÞeÄi ukládat dvojice klÃÄ/hodnota.
- Jak
klÃÄ, takhodnotamusejà být ÅetÄzce. - Omezenà velikosti je 5 MB nebo vÃce, závisà na prohlÞeÄi.
- Tato data neexpirujÃ.
- Data jsou vázána na původ (doména/protokol/port).
localStorage |
sessionStorage |
|---|---|
| SdÃlena mezi vÅ¡emi záložkami a okny se stejným původem | Viditelná uvnitÅ záložky prohlÞeÄe vÄetnÄ vnitÅnÃch rámů se stejným původem |
| PÅežije restart prohlÞeÄe | PÅežije znovunaÄtenà stránky (ale ne zavÅenà záložky) |
API:
setItem(klÃÄ, hodnota)â uložà dvojici klÃÄ/hodnota.getItem(klÃÄ)â vrátà hodnotu podle klÃÄe.removeItem(klÃÄ)â odstranà klÃÄ s jeho hodnotou.clear()â vymaže vÅ¡e.key(index)â vrátà klÃÄ na poziciindex.lengthâ poÄet uložených dvojic.- K zÃskánà vÅ¡ech klÃÄů použijte
Object.keys. - Ke klÃÄům pÅistupujeme jako k vlastnostem objektu, v takovém pÅÃpadÄ se nespustà událost
storage.
Událost storage:
- Spustà se pÅi volánÃ
setItem,removeItem,clear. - Obsahuje vÅ¡echna data o provádÄné operaci (
key/oldValue/newValue),urldokumentu a ukládacà objektstorageArea. - Spouštà se na všech objektech
window, které majà pÅÃstup k úložiÅ¡ti, s výjimkou toho, který ji vygeneroval (uvnitÅ záložky usessionStorage, globálnÄ ulocalStorage).
KomentáÅe
<code>, pro nÄkolik Åádků je obalte znaÄkou<pre>, pro vÃce než 10 Åádků vložte odkaz na pÃskoviÅ¡tÄ (plnkr, jsbin, codepenâ¦)