Introduzione
Quando un’applicazione JavaScript recupera dati da un’API, può essere utile conservarli temporaneamente per evitare richieste ripetute. Questa tecnica si chiama cache. Una cache semplice può memorizzare la risposta, la data di creazione e la data di scadenza.
In questo tutorial costruiremo una piccola cache persistente usando tre oggetti globali JavaScript:
- Date, per registrare il momento di salvataggio e verificare la scadenza;
- JSON, per convertire gli oggetti JavaScript in stringhe e viceversa;
- Math, per generare un identificatore casuale e calcolare statistiche semplici sulla cache.
Useremo localStorage come archivio del browser. L’obiettivo è creare una soluzione riutilizzabile che supporti il salvataggio, la lettura, l’eliminazione degli elementi scaduti e la visualizzazione di informazioni diagnostiche.
Codice completo
const CACHE_KEY = "app-cache-v1";
/**
* Legge l´intera cache dal localStorage.
* Se il contenuto non è valido, restituisce un oggetto vuoto.
*/
function leggiCache() {
const contenuto = localStorage.getItem(CACHE_KEY);
if (!contenuto) {
return {};
}
try {
return JSON.parse(contenuto);
} catch (errore) {
console.error("Cache danneggiata:", errore);
return {};
}
}
/**
* Salva l´intera cache convertendola in JSON.
*/
function salvaCache(cache) {
localStorage.setItem(CACHE_KEY, JSON.stringify(cache));
}
/**
* Genera un identificatore breve e casuale.
*/
function generaId() {
const numero = Math.floor(Math.random() * 1000000);
return numero.toString(36);
}
/**
* Inserisce un valore in cache per un certo numero di secondi.
*/
function salvaInCache(chiave, valore, durataSecondi) {
const cache = leggiCache();
const adesso = Date.now();
cache[chiave] = {
id: generaId(),
valore,
creatoIl: adesso,
scadeIl: adesso + durataSecondi * 1000
};
salvaCache(cache);
return cache[chiave];
}
/**
* Recupera un valore dalla cache.
* Restituisce null se la chiave non esiste o se il dato è scaduto.
*/
function leggiDaCache(chiave) {
const cache = leggiCache();
const elemento = cache[chiave];
if (!elemento) {
return null;
}
if (Date.now() >= elemento.scadeIl) {
delete cache[chiave];
salvaCache(cache);
return null;
}
return elemento.valore;
}
/**
* Elimina tutti gli elementi scaduti.
*/
function pulisciCache() {
const cache = leggiCache();
const adesso = Date.now();
let elementiEliminati = 0;
for (const chiave in cache) {
if (adesso >= cache[chiave].scadeIl) {
delete cache[chiave];
elementiEliminati++;
}
}
salvaCache(cache);
return elementiEliminati;
}
/**
* Restituisce informazioni utili sullo stato della cache.
*/
function statisticheCache() {
const cache = leggiCache();
const chiavi = Object.keys(cache);
const adesso = Date.now();
const elementiValidi = chiavi.filter(
chiave => cache[chiave].scadeIl > adesso
);
const dimensioneJson = JSON.stringify(cache).length;
return {
elementiTotali: chiavi.length,
elementiValidi: elementiValidi.length,
dimensioneCaratteri: dimensioneJson,
percentualeValidi: chiavi.length === 0
? 0
: Math.round((elementiValidi.length / chiavi.length) * 100)
};
}
/* Esempio pratico */
const rispostaApi = {
utenti: [
{ id: 1, nome: "Ada" },
{ id: 2, nome: "Luca" }
],
ricevutoDa: "api.example.com"
};
salvaInCache("utenti", rispostaApi, 60);
const dati = leggiDaCache("utenti");
if (dati) {
console.log("Dati recuperati dalla cache:", dati);
} else {
console.log("Dato assente o scaduto: eseguire una nuova richiesta API");
}
console.log("Statistiche:", statisticheCache());
console.log("Elementi eliminati:", pulisciCache()); Spiegazione
Usare Date per controllare la scadenza
Date.now() restituisce il numero di millisecondi trascorsi dal primo gennaio 1970, chiamato comunemente Unix timestamp. È particolarmente comodo per confrontare due momenti senza occuparsi direttamente di giorno, mese o formato dell’orario.
Nel codice, la scadenza viene calcolata così:
const adesso = Date.now();
const scadeIl = adesso + durataSecondi * 1000; La moltiplicazione per 1000 converte i secondi in millisecondi. Se la durata è di 60 secondi, il dato sarà valido fino a un minuto dopo il salvataggio.
Usare JSON per la persistenza
localStorage può memorizzare soltanto stringhe. Per questo motivo usiamo JSON.stringify() prima del salvataggio e JSON.parse() dopo la lettura.
localStorage.setItem("dati", JSON.stringify(oggetto));
const oggetto = JSON.parse(localStorage.getItem("dati")); È importante racchiudere JSON.parse() in un blocco try...catch. Se la stringa è stata modificata, troncata o prodotta da una versione precedente dell’applicazione, il parsing potrebbe generare un errore.
Usare Math per identificatori e percentuali
La funzione Math.random() produce un numero pseudo-casuale compreso tra zero incluso e uno escluso. Moltiplicandolo per un intervallo e applicando Math.floor(), otteniamo un intero:
const numero = Math.floor(Math.random() * 1000000); L’identificatore risultante viene convertito in base 36 tramite toString(36), ottenendo una stringa più breve. Questo identificatore è sufficiente per scopi dimostrativi, ma non deve essere usato per autenticazione o sicurezza: per quei casi è preferibile crypto.randomUUID().
Best practice
- Inserire una versione nella chiave: usare una chiave come
app-cache-v1permette di invalidare facilmente dati incompatibili dopo un aggiornamento. - Gestire gli errori di parsing: i dati salvati nel browser non devono essere considerati sempre validi.
- Memorizzare timestamp numerici: i millisecondi sono più semplici da confrontare rispetto a date formattate come testo.
- Eliminare i dati scaduti: una funzione di pulizia evita che la cache cresca inutilmente.
- Limitare la dimensione:
localStorageha uno spazio ridotto e non è adatto a grandi quantità di dati. - Non salvare informazioni sensibili: qualsiasi script eseguito nella pagina può potenzialmente leggere
localStorage. - Usare JSON per dati serializzabili: funzioni, oggetti
Datecomplessi e valori comeundefinednon vengono conservati sempre come previsto.
Riepilogo
Abbiamo creato una cache temporanea e persistente combinando tre oggetti globali fondamentali. Date ha gestito il tempo di creazione e scadenza, JSON ha permesso di salvare oggetti strutturati in localStorage, mentre Math ha contribuito alla generazione di identificatori e al calcolo delle percentuali.
La stessa architettura può essere estesa per memorizzare risultati di ricerca, configurazioni, risposte API o dati temporanei di un’interfaccia web.
