CACHE con JavaScript, tiempo de expiración y LocalStorage

KodotiLocaleCache es una clase que nos va a facilitar la vida para usacar localStorage como sistema de cache.

Rodríguez Patiño, Eduardo
2020-10-01 | 1,289 lecturas

En mis ratos de ocio, decidí crear una clase para implementar cache con tiempo de expiración usando localStorage y que sea fácil de usar para cualquiera. Algo similar a lo que tenemos con el memoryCache para los que vienen de .NET o Memcache para los PHPeros.

KODOTI LOCALE CACHE

La idea es que la implementación sea de forma declarativa, es decir solo nos enfoquemos en la solución, pues la lógica del código ya esta resuelto.

class KodotiLocalCache {
    constructor(key) {
        if (!window.localStorage) {
            throw 'KodotiLocalCache is not supported ..';
        }

        if (!key) {
            throw 'Key was not provided ..';
        }

        this._key = key.toUpperCase() + '.';
    }

    static get TIMETYPE() {
        return {
            SECONDS: 0,
            MINUTES: 1,
            HOURS: 2,
            DAYS: 3,
            CUSTOM: 4
        };
    }

    _prepareKey(key) {
        return this._key + key;
    }

    get(key) {
        key = this._prepareKey(key);

        let result = localStorage.getItem(key);

        if (result) {
            result = JSON.parse(result);

            if (!result.expire) {
                return result.value;
            }

            if (result.expire >= new Date().getTime()) {
                return result.value;
            }

            localStorage.removeItem(key);
        }

        return null;
    }

    add(key, value, time = null) {
        key = this._prepareKey(key);

        // object to store
        let item = {
            key,
            value,
            expire: _fromTime(time)
        };

        localStorage.setItem(key, JSON.stringify(item));

        // time logic
        function _fromTime(time) {
            if (!time) {
                return null;
            }

            let date = new Date();

            if (typeof time === 'number') {
                date.setMinutes(date.getMinutes() + time);
            } else {
                switch (time.type) {
                    case 4:
                        date.setTime(time.value);
                        break;
                    case 3:
                        date.setDate(date.getDate() + time.value);
                        break;
                    case 2:
                        date.setHours(date.getHours() + time.value);
                        break;
                    case 1:
                        date.setMinutes(date.getMinutes() + time.value);
                        break;
                    case 0:
                        date.setSeconds(date.getSeconds() + time.value);
                        break;
                }
            }

            console.log(date);
            console.log(date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds());

            return date.getTime();
        }
    }

    clear() {
        for (let key in localStorage) {
            if (key.includes(this._key)) {
                localStorage.removeItem(key);
            }
        }
    }

    delete(key) {
        key = this._prepareKey(key);
        localStorage.removeItem(key);
    }

    credits() {
        console.log('Developed by Kodoti.com');
    }
}

1. INSTANCIANDO LA CLASE

Se inicializa de la siguiente manera:

let kodotiCache = new KodotiLocalCache('kodoti');

Nota: Es necesario definir un KEY el cual es pasado como parámetro del constructor. Esta va a permitir agrupar los KEYS generados en localStorage comenzando por este prefijo.

2. ASIGNADO UN VALOR AL CACHE

Para esto hacemos uso del método ADD y espera como parámetros:

  • Key: la clave única para este registro.
  • Value: el valor a persistir.
  • Time: el tiempo a vivir en el cache, el cual se espera un valor del tipo entero, objeto o nulo.
kodotiCache.add('test-1', true, 2)

Este valor será persistido por 2 minutos en el cache ..

kodotiCache.add('test-2', {a: 1, b: 2}, {type: KodotiLocalCache.TIMETYPE.HOURS, value: 1})

Este valor será persistido por el tiempo que determinemos en el cache ..

  • KodotiLocalCache.TIMETYPE.SECONDS: valor en segundos hasta antes de expirar.
  • KodotiLocalCache.TIMETYPE.MINUTES: valor en minutos hasta antes de expirar.
  • KodotiLocalCache.TIMETYPE.HOURS: valor en horas hasta antes de expirar.
  • KodotiLocalCache.TIMETYPE.DAYS: valor en días hasta antes de expirar.
  • KodotiLocalCache.TIMETYPE.CUSTOM: valor en milisegundos hasta antes de expirar.
kodotiCache.add('test-3', 'hola', null)

Este valor será persistido sin tiempo de expiración ..

Desde la consola del browser podemos ver los valores asignados.

3. OBTENIENDO UN REGISTRO

Para obtener la información hacemos uso del método GET y retornará el valor en el tipo especificado en un comienzo. Es decir que si persistimos un boolean, nos retornará boolean evitando la tarea de hacer un cast manualmente.

let value = kodotiCache.get('test-3')
if(!value) {
    console.log('El valor no existe o ha expirado');
}

En caso de haber expirado o no existir retornará NULL, por lo cual sería una buena prácticar validar siempre.

4. ELIMINANDO UN REGISTRO

Para eliminar un registro de nuestro CACHE debemos llamar al método DELETE.

kodotiCache.delete('test-3')

5. ELIMINANDO TODO

Para eliminar todos nuestros registros en el CACHE haremos uso del método CLEAR.

kodotiCache.clear()

Esto solo eliminará los KEYS que especificamos en nuestra instancia evitando eliminar otros keys por parte de tu aplicativo o terceros.

¿DÓNDE USARLO?

Por ejemplo en un proyecto lo usé para persistir un JSON que consultaba del servidor. Dicha información era por cliente y siempre se consultaba lo mismo, entonces lo que hicimos fue que se consultara la primera vez por AJAX y la segunda buscará en el localStorage. Asimismo, este proceso se refrescaba cada 20 minutos.