Student starter code (30% baseline)
index.html
- Main HTML pagescript.js
- JavaScript logicstyles.css
- Styling and layoutpackage.json
- Dependenciessetup.sh
- Setup scriptREADME.md
- Instructions (below)💡 Download the ZIP, extract it, and follow the instructions below to get started!
This template demonstrates advanced caching strategies using localStorage with TTL (Time To Live) expiration, performance optimization, and intelligent cache management for API data.
activity-08-caching/
├── index.html # Caching dashboard with data sections
├── styles.css # Cache visualization and responsive styling
├── script.js # Comprehensive caching implementation
├── package.json # Project configuration
└── README.md # This documentation
python3 -m http.server 8002
http://localhost:8002
class CacheManager {
async setCache(key, data, ttl = 300000) { // 5 minutes default
const cacheData = {
data: data,
timestamp: Date.now(),
expiry: Date.now() + ttl,
ttl: ttl
};
localStorage.setItem(`cache_${key}`, JSON.stringify(cacheData));
}
getCache(key) {
const cached = localStorage.getItem(`cache_${key}`);
if (!cached) return null;
const cacheData = JSON.parse(cached);
// Check expiration
if (Date.now() > cacheData.expiry) {
this.removeCache(key);
return null;
}
return cacheData;
}
}
async loadDataWithCache(cacheKey, fetchFunction) {
// Try cache first
const cached = this.getCache(cacheKey);
if (cached) {
console.log('Cache hit!');
return cached.data;
}
// Cache miss - fetch from API
console.log('Cache miss - fetching from API');
const data = await fetchFunction();
// Cache the fresh data
await this.setCache(cacheKey, data);
return data;
}
// Check if cache entry is expired
isExpired(cacheData) {
return Date.now() > cacheData.expiry;
}
// Set custom TTL for different data types
setCacheWithCustomTTL(key, data, minutes) {
const ttl = minutes * 60 * 1000; // Convert to milliseconds
return this.setCache(key, data, ttl);
}
handleStorageQuotaExceeded() {
const oldestKey = this.findOldestCacheKey();
if (oldestKey) {
this.removeCache(oldestKey);
console.log('Removed oldest cache entry due to quota limit');
}
}
const cacheFirst = async (key, fetchFunction, ttl = 300000) => {
const cached = cacheManager.getCache(key);
if (cached) return cached.data;
const data = await fetchFunction();
await cacheManager.setCache(key, data, ttl);
return data;
};
const networkFirst = async (key, fetchFunction, ttl = 300000) => {
try {
const data = await fetchFunction();
await cacheManager.setCache(key, data, ttl);
return data;
} catch (error) {
const cached = cacheManager.getCache(key);
if (cached) return cached.data;
throw error;
}
};
const staleWhileRevalidate = async (key, fetchFunction, ttl = 300000) => {
const cached = cacheManager.getCache(key);
if (cached) {
// Return cached data immediately
// Revalidate in background
fetchFunction().then(data => {
cacheManager.setCache(key, data, ttl);
}).catch(console.error);
return cached.data;
}
// No cache - fetch fresh data
const data = await fetchFunction();
await cacheManager.setCache(key, data, ttl);
return data;
};
updateStats() {
const total = this.stats.hits + this.stats.misses;
const hitRate = total > 0 ? ((this.stats.hits / total) * 100).toFixed(1) : 0;
console.log(`Cache Hit Rate: ${hitRate}%`);
}
calculateStorageUsage() {
let totalSize = 0;
const keys = Object.keys(localStorage).filter(key => key.startsWith('cache_'));
keys.forEach(key => {
totalSize += localStorage.getItem(key).length;
});
return totalSize < 1024 ? `${totalSize} B` : `${(totalSize / 1024).toFixed(1)} KB`;
}
// Replace mock APIs with real endpoints
class RealAPIService {
async fetchUsers() {
const response = await fetch('/api/users');
if (!response.ok) throw new Error('API request failed');
return response.json();
}
async fetchWithCache(endpoint, cacheKey, ttl = 300000) {
return CacheUtils.cacheFirst(cacheKey, () =>
this.fetchAPI(endpoint), ttl
);
}
}
// Example React hook for cached data
function useCachedData(key, fetchFunction, ttl = 300000) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
CacheUtils.cacheFirst(key, fetchFunction, ttl)
.then(setData)
.finally(() => setLoading(false));
}, [key]);
return { data, loading };
}
Next Steps: Continue with Activity 9 (Error Handling) to learn robust error management that complements caching strategies.