Kawałek Kodu

Każdy z nas ma skłonności do chomikowania. Zbieramy wszystko co można sobie wyobrazić: widokówki, znaczki, cukry, pudełka, itd. I nie jest to bez znaczenia, bo zawsze lepiej mieć coś pod ręką na tzw. wszelki wypadek niż drapać się w głowę zastanawiając się skąd wziąć, jeśli zajdzie nagła potrzeba. Jest to po prostu szybsze i ekonomiczniejsze. I tą zasadą warto się kierować również przy programowaniu, dlatego stworzymy dziś prosty cache do przechowywania wartości.

Pudełko pełne wartości.

Będziemy potrzebować pojemnika, w którym pod danym kluczem można będzie zapisać wartość, a podając klucz odczytać wartość jeśli istnieje. Wykorzystamy obiekt localStorage. W tej chwili można by się zatrzymać i zapytać po co cache, skoro właśnie localStorage może pełnić (pełni?) taką funkcję. Dostarcza metody getItem i setItem, więc wystarczy w razie potrzeby zapisywać i odczytywać dane.

Spróbujmy więc zapisać obiekt jako wartość:

localStorage.setItem("klucz", { 0: "abc", 1: "def" });
console.log(localStorage.getItem("klucz"));

Co otrzymasz? [object Object] - nie obiekt, lecz string, ponieważ metoda setItem wywołuje na przekazanej wartości (tu obiekcie) metodę toString. Zapisany obiekt został więc bezpowrotnie utracony. Można powiedzieć: co za cacheana!

Nie chcę Cię stracić!

Jak przechowywać obiekty w localStorage? Z pomocą przyjdzie nam obiekt JSON i jego metody: stringify oraz parse, dzięki którym bez zbędnego wysiłku upakujemy wartości w pudełku, a te nie wylecą dnem. Metoda stringify zamienia obiekt na postać tekstową JSON (to nie jest toString), a metoda parse wykonuje operację odwrotną. Nasz przykład wyglądałby tak:

localStorage.setItem("klucz", JSON.stringify({ 0: "abc", 1: "def" }));
console.log(JSON.parse(localStorage.getItem("klucz")));

Tym razem otrzymamy {0: "abc", 1: "def"}.

Czas to cache!

Znów można powiedzieć: no to skrypt do cache załatwiony! Nie całkiem, bo chcemy mieć również możliwośc ustalania czasu życia naszej wartości, czyli przez jaki czas możemy uznać ją za prawidłową kiedy pobieramy ją z cache. Wraz z wartością będziemy zapisywać więc znacznik czasowy, który powie o momencie nieważności wartości. Ponieważ w localStorage nie można zapisać dwóch wartości pod jednym kluczem, to wartość i znacznik czasowy przechowamy w jednym obiekcie: {value: wartosc, expirationDate: do_kiedy_wazna}.

No dobra, to czas aby pokazać skrypt:

class Hamster {
  constructor() {
    this.storage = localStorage;
  }
  getItem(key) {
/* jeśli wartość istnieje */
    if (this.storage.getItem(key)) {
/* odczytujemy ją i parsujemy
   String->Object
*/
      const item = JSON.parse(this.storage.getItem(key));
/* Jeśli data ważności jest teraźniesza
   lub późniejsza to zwracamy wartość,
   jeśli nie to usuwamy wartość i zwracamy
   false
*/
      if (item.expirationDate >= Date.now()) {
        return item.value;
      } else {
        this.storage.removeItem(key);
      }
    }
    return false;
  }
  putItem(key, value, lifetime = 60) {
/* czy klucz i wartość są zdefiniowane
   i niepuste,
   jeśli tak, to zapisujemy pod danym kluczem
   obiekt złożony z wartości
   oraz daty ważności jako string
*/
    if (key && value) {
      this.storage.setItem(
        key,
        JSON.stringify({
          value: value,
          expirationDate: Date.now() + lifetime
        })
      );
    }
  }
}

/* użycie */
const hamster = new Hamster();
let found;

/* zapisujemy obiekt wraz z URL */
hamster.putItem("/szukaj.php?fraza=Czer", {
  0: "ul. Czerwona 2",
  1: "ul. Czerniakowska 3"
});

/* odczytujemy wartość spod URL */
found = hamster.getItem("/szukaj.php?fraza=Czer");
console.log(found);

/* tu zapis i odczyt "płaskiej" wartości */
hamster.putItem("/index.php", "Jakiś tekst");
found = cache.getItem("/index.php");
console.log(found);

Po co taki skrypt? Myślę, że przyda się bardzo przy zapytaniach Ajaxowych gdzie często wysyłamy żądania, np. funkcjonalności autocomplete. Kluczem będzie oczywiście URL. Zanim wyślemy kolejne żądanie, sprawdzamy czy w cache istnieje wartość pod danym URL (kluczem), jeśli tak, to zwracamy ją, a zapytania nie musimy wysyłać. Możemy również przechowywać wyniki skomplikowanych obliczeń, których nie chcemy lub nie musimy wykonywać ponownie.

Powodzenia w zbieractwie (wartości!). Do przeczytania w kolejnym wpisie.

Przydatne linki:
Metoda setItem obiektu localStorage
Metoda getItem obiektu localStorage
Metoda parse obiektu JSON
Metoda stringify obiektu JSON