Często potrzebujemy po stronie klienta przechowywać różnego rodzaju dane, które aplikacja internetowa może potem wykorzystywać. Ciasteczka niezbyt do tego się nadają. Z pomocą przychodzi nam localStorage.

Czym jest localStorage?

Na stronie w3schools możemy przeczytać kilka zdań o localStorage. Parafrazując:

Za pomocą lokalnego magazynu, aplikacje internetowe mogą przechowywać dane w przeglądarce użytkownika. Przed HTML5, dane aplikacji musiały być przygotowywane w ciasteczkach i powinny być zawarte w każdym żądaniu do serwera. Magazyn lokalny jest bezpieczniejszy i może przechowywać znacznie więcej danych bez wpływu na wydajność.

Najważniejszym punktem tego było dla mnie to, że jest bezpieczniejszy i nie wymaga się aby każdorazowo dbać o niego. Wystarczy raz zapisać i już mamy to dostępne dla naszej “strony”, czyli aplikacji. Plusem (choć w moim wypadku obojętnym) jest wsparcie dla localStorage w każdej współczesnej przeglądarce. Chociaż akurat electron i tak jest zbudowany na chromie. LocalStorage jest też o tyle dobre, że przechwywane jest także po zamknięciu przeglądarki.

Jak skorzystać?

localStorage jest jak słownik. Aby dodać element do tego słownika używamy metodę setItem:

localStorage.setItem("key", "value");

Natomiast jeśli chcemy uzyskać wartość z klucza wywołujemy metodę getItem:

var value = localStorage.getItem("key");

Gdybyśmy chcieli usunąć wartość z klucza, możemy użyć metody removeItem:

localStorage.removeItem("key");

Warto pamiętać, że klucz i wartość są przechowywane jako stringi więc jeśli chcemy przechowywać tam obiekt - musimy go najpierw zserializować a przy odczycie zdeserializować.

A gdzie expiration date?

No właśnie. Tego brakuje. Przynajmniej z mojej perspektywy. ALE. Jak wrzystko - da się obejść. W związku z czym napisałem własną klasę, która na bazie localStorage może wrzucać klucze z pseudo wygaśnięciem:

export class PersistenceCache {
    static cache: Storage = localStorage;

    static setItem(key: string, value: string, expirationDate?: Date) {
        var cacheObj = new CacheObject();
        cacheObj.value = value;
        cacheObj.expireDate = expirationDate;

        PersistenceCache.cache.setItem(key, JSON.stringify(cacheObj));
    }

    static getItem(key: string) {
        var cacheJson = PersistenceCache.cache.getItem(key);
        if(cacheJson) {
            var cacheObject = JSON.parse(cacheJson);
            var expDate = cacheObject.expireDate;
            var now = new Date();

            if (expDate && expDate < now){
                PersistenceCache.cache.removeItem(key);
                return null;
            }

            return cacheObject.value;
        }
    }

    static removeItem(key: string) {
        PersistenceCache.cache.removeItem(key);
    }
}

class CacheObject {
    value: string;
    expireDate?: Date;
}

Generalnie zasada opiera się na wygaśnięciu sprawdzanym podczas odczytu. Czyli jeśli okaże się, że data wygaśnięcia już minęła to w tym momencie usuwamy dany obiekt i zwracamy null;

Co dalej?

No tak. Co dalej? Odwieczne pytanie :) Bez planu nie da się nic dalej zrobić, dlatego kolejnym krokiem będzie planowanie. I o tym planowaniu troszkę w kolejnym poście. Najpierw opiszę kilka kroków jak sam się do tego zabieram, następnie zaplanuję sobie rzeczy do zrobienia i ich kolejność oraz wybiorę inspirację do UI aplikacji.

Do następnego razu!