Pamięć Cache. Czyli wszystko co musisz o niej wiedzieć jako Web Dev.

Czy zastanawiałeś/aś się kiedyś dlaczego strony ładują się szybciej przy kolejnych wizytach? Jaką rolę ma w tym wszystkim przeglądarka? Na ile wpływ ma na to Developer który tworzy stronę lub aplikację? Jak ma się do tego wszystkiego słowo Cache? Skąd ono się w ogóle wzięło i po co Ci ta wiedza? O tym wszystkim dowiesz się w tym artykule!

Czego się dzisiaj dowiesz?

Dzisiaj opowiem czym jest pamięć Cache. Skąd się ona wzięła i jak ten mechanizm jest wykorzystywany w przeglądarkach internetowych. Trochę historii, trochę teorii i praktycznych wskazówek dla Ciebie- pasjonata internetu 🙂 Jego kreatora. Web Developera!

Nawet jeśli wydaje Ci się, że znasz już to zagadnienie to i tak przeczytaj 🙂 Tak dla odświeżenia 🙂

Dlaczego to piszę?

W Web Developmencie są tematy traktowane pobieżnie. Zazwyczaj to te które nie kojarzą się z chwytliwymi hasłami typu “React” itp. Ja tam lubię zrobić czasem krok w tył i dobrze zrozumieć stosunkowo podstawowe mechanizmy. Do takich mechanizmów należy pamięć Cache w przeglądarce.

Od czego zacząć?

Jak zwykle 🙂 Od początku 🙂

Pamięć Cache- skąd się wzięła?

Pamięć Cache to specjalny bardzo szybki rodzaj pamięci który został wynaleziony w celu usprawnienia komunikacji między procesorem w komputerze a nośnikiem pamięci. Lata temu gdy procesory komputerów stawały się coraz szybsze zauważono, że szybkość obliczeń wcale nie wzrasta pomimo lepszych parametrów procesorów. Powodem tego były niższa wydajność pamięci operacyjnej (RAM) i nośników pamięci.

Aby ominąć ten problem wymyślono specjalny rodzaj pamięci o wysokich parametrach i bardzo małej pojemności który nazwano Cache. Zadaniem cache było buforowanie danych i podawanie ich do procesora aby ten mógł wydajnie pracować. Bardzo fajnie zostało to wytłumaczone w tym artykule

Powyższy artykuł wprowadza też bardzo trafne porównanie gdzie porównuje mechanizm cache do młodego naukowca:

Młody naukowiec to procesor, jego asystentka obsługująca jego półkę czy pokój z materiałami to pamięć Cache, lokalna biblioteka to pamięć operacyjna RAM a ogół dostępnej literatury to nośnik pamięci (dysk twardy).

Cache i internet

Mechanizm cache został zapożyczony do obsługi internetu. Nie jest to dokładna analogia ale słowo cache w tym wypadku jest porównaniem które trafnie odzwierciedla to co się dzieje w wypadku przeglądania aplikacji internetowych.

Wracając do naszego naukowca:

Młody naukowiec to… TY 🙂 Czyli użytkownik internetu.

Twoja przeglądarka to Twoja… Asystentka. To tu działa pamięć cache.

Serwer na którym jest Twoja aplikacja to lokalna biblioteka.

Zewnętrzne API i serwisy których używa aplikacja to część ogółu dostępnej literatury.

Proste co nie?

Pamięć Cache w przeglądarce – local cache.

Jedziemy dalej. Tak jak w przypadku Cookies czy localStorage przeglądarka alokuje miejsce na dysku twardym Twojego komputera gdzie zapisuje pliki pobrane z serwera na którym znajduje się strona/aplikacja którą właśnie odwiedzasz.

Przy każdej kolejnej wizycie przeglądarka sprawdza jakie zasoby są na serwerze a jakie w pamięci cache. Jeśli dane zasoby są już na dysku użytkownika to ich nie pobiera z serwera tylko wyświetla na stronie. W ten sposób zmniejsza się ilość danych do pobrania a aplikacja/strona ładuje się szybciej. Działa to dość dobrze zwłaszcza w przypadku stron z dużą ilością grafik.

Ilość miejsca na dysku jakie przeglądarka może użyć do przechowywania danych w cache można zmienić jednak więcej nie zawsze znaczy lepiej 🙂 Jak chcesz zobaczyć jak to się robi możesz sprawdzić np. ten artykuł.

Shared / proxy cache

Drugim typem pamięci cache jest tzw. shared lub proxy cache. Ma on zastosowanie w miejscach, gdzie wiele komputerów połączonych w sieć łączy się z internetem za pośrednictwem lokalnego serwera. Przykładem takiego środowiska może być duża firma która ma wiele komputerów.

Ten mechanizm jest pomocny o tyle, że zanim przeglądarka pobierze dane z serwera aplikacji to najpierw sprawdzi czy nie ma tych danych na serwerze firmowym/lokalnym. Jest to super kiedy pracownicy korzystają np. z facebooka i renderują generalnie podobne treści 🙂 Wtedy łącze internetowe oszczędza sporo transferu 🙂

Wróćmy jednak do naszego lokalnego cache bo to jest głównym tematem Naszych rozważań…

Skąd przeglądarka wie co pobrać?

Za każdym razem gdy użytkownik wpisuje adres URL w przeglądarce automatycznie wysyłany jest HTTP GET request. Żądanie GET jest równoznaczne ze stwierdzeniem pobierz zasoby z danego serwera i jeśli się da to je wyświetl. Zakładając, że wszystko poszło OK serwer zwraca nam status 200 i wysyła co tam ma w swoich zasobach.

Headers

Serwer i Klient (przeglądarka) w swojej komunikacji używają tzw. headers’ów czyli nagłówków zawierających konkretne informacje. Rozwinę ten temat nieco później.

Trochę praktyki

Zaraz to wszystko się rozjaśni bo będzie praktyczny przykład.

Komunikację między klientem a serwerem można podejrzeć w DevTools wbudowanych w każdej współczesnej przeglądarce. Aby je uruchomić wystarczy kliknąć prawym przyciskiem w dowolnym miejscu w obrębie okna strony i wybrać opcję Zbadaj/Inspect i iść do zakładki Sieć/Network.

Generalnie żaden Web Developer nie powinien mieć z tym problemu bo doskonale zna DevTools 🙂

Praktyczny przykład

Za chwilę zrobię eksperyment i sprawdzę jak ładuje się strona przy pierwszej wizycie, a jak przy kolejnej. Zobaczę czy i jak działa mechanizm cache. Dla urozmaicenia wybiorę stronę bedekodzic.pl 🙂

Hard Reload

Generalnie praktycznie każdy zna bloga bedekodzic.pl więc znalezienie przeglądarki która jeszcze go nie odwiedziła to ciężka sprawa 🙂 Ale można to obejść używając np. hard reload’a

Przy każdym normalnym odświeżeniu strony mechanizm cache zostaje uruchomiony. Jeśli zastosujemy hard reload to przeglądarka pobiera wszystkie zasoby z serwera ignorując pamięć cache. Jeśli nie wiesz jak zrobić taki hard reload w Twojej przeglądarce to możesz o tym przeczytać np. tutaj

Bedekodzic.pl

No to załaduję mojego bloga w Chromie za pomocą hard reload’a analizując przy tym połączenie:

Zwróć uwagę na podświetlone punkty 1 i 2.

1 – aby załadować stronę przeglądarka musiała pobrać 88 plików o łącznej wielkości 2.1MB zajęło to 25s ( hehe siedzę teraz na LTE i GB mi się skończyły 😛 )

2 – pliki o danym rozmiarze zostały załadowane z serwera.

Teraz spróbujmy załadować stronę po raz kolejny po prostu ją odświeżając:

1 – znowu pobraliśmy 88 plików tylko tym razem zużyliśmy 208KB transferu. To tylko 10% w porównaniu z pierwszym ładowaniem. Co się stało się?

2 – tu widać, że przeglądarka pobierała pliki z memory/disk cache. Jaka jest różnica między nimi? To sposób w jaki Chrome implementuje cache. Więcej info np. w dyskusji tutaj

Właśnie tak działa cache! Zachęcam do samodzielnego sprawdzenia tego mechanizmu. Najlepiej na przykładzie bedekodzic.pl 🙂

Jak kontrolować cache?

Do tego służy mechanizm cache-control i wspomniane wcześniej hedears’y (nagłówki). Aby kontrolować cache należy poustawiać odpowiednio nagłówki. Zanim powiem gdzie te nagłówki ustawiać to trochę o tym jak te nagłówki wyglądają i co możemy w nich definiować.

Żądanie

Wrócę do DevToolsów. Otóż klikając na dowolny plik w analizie połączenia przeglądarki z serwerem możemy podejrzeć wszystkie nagłówki które zostały wysłane/odebrane. Wygląda to tak:

Na czerwono podświetliłem nagłówki które są dla nas szczególnie interesujące w kontekście cache. Na pierwszy ogień idzie:

Cache-Control

Ten nagłówek definiuje czy i jak ma działać mechanizm cache. Może on przybierać wartości:

public

Ta wartość pozwala na użycie cache w każdej jej odmianie tzn. local, proxy itp.

private

Możliwość użycia tylko local cache w przeglądarce.

no-store

Cache jest wyłączone i za każdym razem zasób jest pobierany z serwera.

no-cache

Hehe ta nazwa jest nieco myląca bo w tym wypadku cache działa tylko… zanim załaduje zasób to sprawdza nagłówek ETag

ETag

Ten nagłówek to unikalny token przypisany do każdego pliku/zasobu. Jeśli mamy do czynienia z no-cache to przeglądarka najpierw sprawdza ETag zasobu i nawet jeśli plik jest pozornie ten sam a ETag jest inny znaczy to tyle, że jest to inny plik. Najprawdopodobniej nowsza wersja. W tym wypadku zasób jest pobierany z serwera.

Content-Type

Tu sprawa jest jasna. Ten nagłówek określa typ pliku.

Date

Określa kiedy zasób został pobrany do pamięci. Od tego momentu liczone jest jak długo plik ma być przechowywany w pamięci cache.

URL Fingerprint

Czytając uważnie pewnie zauważyłeś pewną zastanawiającą kwestię. Skoro korzystając z no-cache pliki identyfikowane są za pomocą ETaga to jak są identyfikowane gdy nie używamy no-cache?

Wtedy identyfikowaneponazwie. I tu pojawia się problem…

Jeśli nowa wersja pliku np. .css została wrzucona na serwer i ma taką samą nazwę jak stary plik to przeglądarka mając w pamięci cache stary plik o tej samej nazwie nie załaduje nowego pliku. W związku z tym użytkownik nie będzie widział nowych styli o ile nie zrobi hard reload’a albo cykl życia pliku w pamięci cache się nie skończy i plik nie zostanie usunięty.

Może czasem pracując nad swoim projektem zauważyłeś/aś, że przeglądarka potrafi nie załadować nowych styli CSS. To przez pamięć cache.

Aby poradzić sobie z tym problemem można użyć techniki URL Fingerprinting.

Zasada jest bardzo prosta. Po prostu każdy plik wysłany na serwer powinien mieć swoją wersję w nazwie tzn. style_v1.css, style_v2.css itp. W ten sposób serwujemy zawsze ten plik który chcemy.

Cykl życia pliku

Skoro już wiemy jak działają headers’y to sprawdźmy jak możemy ich użyć!

Wspomniałem już o cyklu życia plików. Otóż cała sztuka w kontekście cache polega na tym, aby określić jakie typy plików jak długo mają być przechowywane w pamięci cache. Po upływie danego terminu przeglądarka usuwa dany plik i nie blokuje on już miejsca na dysku.

Jakie pliki możemy cache’ować?

Poniżej kilka ogólnych przykładów. Nie należy się absolutnie sugerować podanymi okresami 🙂 Sam/a decydujesz.

  1. Grafiki – (png, jpg, gif, itp.) – zazwyczaj ciężkie i rzadko zmieniane więc można ustawić pamięć np. na kilka miesięcy/rok
  2. Favicony – (ico) – podobnie jak grafiki
  3. JSy – (js) – trochę krócej niż grafiki np. miesiąc
  4. CSSy, HTMLe – (css, html) – tu zmiany są raczej najczęstsze więc np. tydzień

Gdzie to wszystko definiować?

Skoro już wiemy co mamy definiować to trzeba wiedzieć gdzie to definiować.

  1. Można to zrobić na Back-Endzie np. w PHP.
  2. Kiedyś robiono to za pomocą metatagów w HTML, praktyka porzucona.
  3. Używając pliku .htaccess

Plik .htaccess

Ten plik pozwala na dodatkową konfigurację serwera przez Developera. Nie będę się tu na jego temat rozwodził ale jeśli jeszcze nie wiesz o co chodzi to zapraszam do przeczytania mojego wpisu na ten temat

Jak zdefiniować pamięć cache?

Należy to zrobić w pliku .htaccess jednak sposób będzie się nieco różnić w zależności od tego jakiego serwera używamy np. Apache czy NGiNX

Apache

# One year for image files
<filesMatch ".(jpg|jpeg|png|gif|ico)$">
Header set Cache-Control "max-age=31536000, public"
</filesMatch>

# One month for css and js
<filesMatch ".(css|js)$">
Header set Cache-Control "max-age=2628000, public"
</filesMatch>

Długość życia pliku ustawiamy za pomocą max-age i definiujemy go w sekundach.

NGiNX

location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {

expires 365d;

}

Tutaj expires ustawiony w dniach.

Jeśli chcesz ustawić cache dla konkretnego pliku możesz spróbować np. tego sposobu. 

Co dalej?

Oczywiście podane przeze mnie przykłady są dość ogólne i jeśli potrzebujesz to wszystko spersonalizować będzie potrzeba nieco pracy własnej. Na początek zapraszam do zapoznania się z dokumentacją na MDN. To prawdziwa skarbnica wiedzy.

Jeśli chodzi o mnie to na dzisiaj już będzie tyle 🙂

Podsumowanie

Pamięć cache to bardzo przydatne narzędzie które zwiększa szybkość stron i aplikacji. Jako Web Developer dobrze orientować się w temacie.

Jeśli ten wpis zawiera jakieś błędy logiczne lub uważasz, że pominąłem jakąś ważną kwestię to napisz o tym proszę w komentarzu. Powiem więcej, jeśli ten wpis zwyczajnie Ci się podobał to też skrobnij jakiś komentarz 🙂


Bartek Cis

Piszę dla was tego bloga bo lubię aplikacje internetowe. Mogę je projektować, kodować a potem o nich pisać czując dreszczyk ekscytacji za każdym razem gdy trafię na coś nowego. Bo uczymy się całe życie. Prawda?