Lekce 6 - Datová úložiště v JavaScriptu
V předešlém cvičení, Řešené úlohy k 4.-5. lekci OOP v JavaScriptu, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
V dnešní lekci si představíme jakými způsoby můžeme v JavaScriptu ukládat data tak, abychom je při obnovení stránky hned zas neztratili.
Web storage
Web storage, neboli DOM Storage, je souhrnný název pro úložiště
localStorage
a sessionStorage
.
localStorage
localStorage
je úložiště v internetovém
prohlížeči uživatele (proto local), do kterého se mohou ukládat
data v textovém řetězci, ke kterým můžeme později
přistupovat. K dispozici máme pro naši aplikaci 10MB prostoru, což je pro
texty opravdu hodně Možnost
ukládat jen text je poměrně omezující, ale stejně je
localStorage
kvůli své jednoduchosti nejoblíbenějším
úložištěm dat, o která nechceme po obnovení nebo zavření stránky
přijít.
Práce s localStorage
S localStorage
se pracuje velmi jednoduše.
setItem()
K uložení nějakého řetězce pod textový index použijeme metodu
setItem()
. Zkusme si pod klíč "jmeno"
uložit string
"Karel"
:
localStorage.setItem("jmeno", "Karel");
Stránku se skriptem otevřeme v prohlížeči, kód následně smažeme a stránku zas obnovíme. Tím jsme si jistí, že Karla již nikde v kódu nemáme, ale je uložený v úložišti.
getItem()
Analogicky pro přečtení hodnoty pod klíčem použijeme
getItem()
. Nyní si vypíšeme co je pod klíčem
"jmeno"
, čímž získáme hodnotu "Karel"
:
document.write(localStorage.getItem("jmeno"));
Výsledek:
Vidíme, že se Karel opravdu načetl.
removeItem()
Asi vás nepřekvapí, že řetězec pod nějakým klíčem můžeme z
úložiště i vymazat. Uděláme to metodou removeItem()
:
localStorage.removeItem("jmeno");
clear()
Úložiště můžeme kompletně vyprázdnit od všech klíčů a dat pod
nimi metodou clear()
.
length
Počet položek v localStorage
získáme pomocí vlastnosti
length
:
document.write("Uloženo " + localStorage.length + " položek");
Výsledek:
key()
Možná vás napadlo, jak zjistíme, co vše je v localStorage
uloženo nebo jak s položkami v úložišti pracovat hromadně. Poslední
chybějící metoda je proto key(n)
, kde n
je index -
pořadové číslo klíče, který chceme vrátit. V kombinaci s vlastností
length
tak dokážeme např. vypsat všechny klíče v úložišti
a hodnoty pod nimi uložené. Udělejme si poslední ukázku, čímž opravdu
vyčerpáme možnosti, které localStorage
nabízí:
for (let i = 0; i < localStorage.length; i++) { const klic = localStorage.key(i); document.write(klic + ": " + localStorage.getItem(klic) + "<br>"); }
Výsledek:
Kód uloží do localStorage
3 hodnoty pod 3 klíče a
následně vypíše počet položek v úložišti.
Pořadí klíčů může být v každém prohlížeči jiné
a proto by na něm naše aplikace neměla záviset. Neměli bychom tedy např.
předpokládat, že prvně přidaná hodnota bude vždy pod klíčem
0
.
Uložení více hodnot pod jeden klíč
Možná přemýšlíte, jakým způsobem je možné uložit např. pole hodnot nebo objekt pod jeden klíč úložiště? Pokud bychom související hodnoty neseskupovali pod jeden klíč, byl by v úložišti opravdu nepořádek, jen si zkuste představit, jak bychom tam uložili 2 uživatele. Proto si celý objekt převedeme na text, což se v JavaScriptu dělá pomocí formátu JSON. To se naučíme hned v příští lekci a potom si to i prakticky vyzkoušíme na našem OOP diáři.
sessionStorage
Kromě localStorage
existuje také úložiště
sessionStorage
. To funguje úplně stejně, ale liší se v
kontextu, v kterém jsou data uložena. Rozdíly jsou 3:
- Data v
sessionStorage
jsou unikátní pro každou záložku prohlížeče. Když si naopak otevřeme tu samou stránku používajícílocalStorage
ve více záložkách, budou všechny záložky používat to samé úložiště s těmi stejnými daty. - Data budou ztracena ve chvíli zavření záložky. Naopak
data v
localStorage
v prohlížeči zůstávají. - Říkáte si proč tedy
sessionStorage
používat, když se se zavřením stránky stejně smaže? To už bychom přeci mohli data uložit jen do proměnných jako doposud...sessionStorage
podobně jako cookies zůstává netknuté při obnovení stránky nebo při přechodu na jinou stránku v té samé doméně.
Cookies
O sušenkách jste určitě již slyšeli, minimálně v souvislosti s Evropskou Unií a její nechvalně proslulou cookie hláškou:
Sušenky mají hned několik využití, nejdůležitější jsou 3:
- Uložení dat v prohlížeči - Cookies byly dlouhou dobu
jediným způsobem, jak si v prohlížeči něco uložit, aniž by se to při
obnovení stránky ztratilo. Takto jsme si mohli uložit např., že jsme na
stránce již vykřížkovali cookie hlášku K tomuto účelu se v dnešní
době používá nové úložiště
localStorage
, viz dále. Tam se hodnoty z úložiště jednodušeji získávají a nezatěžují šířku pásma, protože se neposílají s každým požadavkem na server. - Přihlašování uživatelů - Jelikož prohlížeč spolu s požadavkem na server odesílá serveru i všechny cookies v dané relaci, realizuje se přes ně přihlášení uživatele na serveru. Jinými slovy, hodnotu cookies uživatele můžeme číst na serveru v jazycích jako je PHP nebo C# .NET. Toto využití je potom popsáno v příslušných serverových kurzech.
- Získání informací o uživateli - Do cookies si Google ukládá, že jste na něm hledali boty. Google reklamy na jiných stránkách si poté načtou z cookies co vás zajímá a dané zboží vám nabízí. Podobně funguje i Google Analytics, jejichž cookie je snad na každé internetové stránce.
V klientském JavaScriptu tedy již pro používání cookies není příliš dobrý důvod, pro úplnost si práci s nimi ale stejně ukážeme, učit se ji nemusíte.
Vytvoření nové cookie
Cookie vytvoříme trochu podivným způsobem a to přiřazením do
proměnné document.cookie
, která obsahuje všechny cookies.
Přiřazení do ní ovšem všechny cookies nepřepíše, ale přidá mezi ně
novou. Aby podivnosti tohoto staršího API nekončily, vytváříme cookie jako
řetězec 4 hodnot oddělených středníky, např. takto:
"eu_hlaska_zavrena=1; expires=Sun, 29 Mar 2020 22:00:00 GMT; path=/"
Cookie zadáváme:
- Název a hodnotu
- Datum expirace - Pokud vynecháme, cookie platí do zavření záložky prohlížeče. Pokud nastavíme do minulosti, cookie se ihned odstraní.
- Cestu - Kde cookie platí, většinou nastavujeme na celou
doménu hodnotou
/
.
Krkolomné vytváření cookie přímo svádí k napsání funkce. Její kód by byl následující:
function vytvorCookie(nazev, hodnota, expirace = null) { const castExpirace = expirace ? `expires=${expirace.toGMTString()};` : ''; document.cookie = `${nazev}=${hodnota}; ${castExpirace} path=/`; } vytvorCookie('eu_hlaska_zavrena', 1, new Date(2020, 2, 30));
Načtení hodnoty cookie
Ani načtení cookie není příliš intuitivní. Musíme si totiž prvně načíst všechny cookies v daném dokumentu, což je dlouhý textový řetězec, ve kterém jsou všechny cookies dané stránky oddělené středníky. Je tam pouze název a hodnota, datum expirace si vnitřně řeší prohlížeč.
Řetězec document.cookie
vypadá např. takto:
_ga=GA1.2.1621812384.1525606041; __gads=ID=fdbec79e49891ee3:T=1525606041:S=ALNI_MYNHHGQJ65wZIjdzOc60pQanykM8w; __qca=P0-718587983-1559900791988; _gid=GA1.2.2042156113.1583272955; _gat=1; eu_hlaska_zavrena=1"
Nyní je na nás, abychom si z něj hodnotu eu_hlaska_zavrena
vypreparovali. Samozřejmě musíme počítat i s tím, že daná cookie vůbec
neexistuje! Funkce pro čtení cookies by vypadala takto:
function najdiCookie(nazev) { const cookies = document.cookie.split(';') for (const cookie of cookies) { hodnoty = cookie.split('='); if (nazev == hodnoty[0].trim()) return hodnoty[1].trim(); } return null; } document.write(najdiCookie('eu_hlaska_zavrena'));
Zkusme si v prohlížeči, že to opravdu funguje:
Jak již bylo řečeno, všechny hodnoty všech cookie se
odesílají na server v hlavičce HTTP požadavku při každém načtení
každé stránky. Proto je používejte jen pokud nemůžete použít
localStorage
.
Cookie nastavená ze serveru může mít nastavenou vlastnost
HttpOnly
, čímž ji z klientského JavaScriptu nemůžeme
načíst. Toto je základní bezpečnostní opatření, které by mělo být
nastaveno při používání cookies k autentizaci uživatelů na serveru. Z
klientského JavaScriptu tato vlastnost pochopitelně cookies nastavit nelze
Odstranění cookie
Odstranění cookie je stejné jako její vytvoření, pouze nastavíme její expiraci do minulosti, což povede k jejímu odstranění. Jako hodnotu můžeme uvést cokoli.
IndexedDb
Posledním standardním úložištěm, které můžeme v JavaScriptu
používat, je IndexedDB. Jak název napovídá, nejedná se již o pouhé
úložiště, kam ukládáme data pod nějakými klíči, ale o plnohodnotnou
databázi s tabulkami a indexy, z čehož také vznikl její název. Ukládáme
tedy strukturovaná data. Databázové indexy nám umožňují v databázi
vyhledávat řádově rychleji a jsme schopní s daty přímo pracovat, aniž
bychom je museli převádět z/do string, jako je tomu u
localStorage
. Navíc podporuje transakce a další standardní
databázové mechanismy, které nám zajistí datovou integritu (že data nejsou
uložena špatně, třeba proto, že v aplikaci došlo k chybě, jednoduše se
uloží buď vše nebo nic). V neposlední řadě podporuje rovněž ukládání
souborů.
Databáze je tzv. NoSQL, to znamená, že s ní nekomunikujeme jazykem SQL, jako to u databází bývá zvykem, ale voláním metod na databázových objektech. To je někdy trochu krkolomné a proto pro ni vzniklo hned několik nástaveb.
IndexedDB je vhodná pro větší aplikace se složitější datovou strukturou a větším množstvím dat. Její používání převyšuje úroveň OOP kurzu a vydalo by na samostatný kurz, proto se s ní zde zabývat nebudeme.
IndexedDB bychom neměli zaměňovat s WebQL, což je jiná nestandardní databáze, která není podporována všemi prohlížeči.
V následujícím kvízu, Kvíz - Datové typy a datová úložiště v JavaScriptu, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.