EN/CH Mode
BRUCE_FE Interview Notes - User Interaction Optimization - Caching Strategies
In-depth analysis of frontend runtime caching mechanisms, including HTTP caching, Web Storage, and offline strategies, providing comprehensive caching knowledge and practical applications for interviews.
EN/CH Mode

Lazy to read articles? Then watch videos!
Basic Concepts
Cache is a technology for temporarily storing data that can speed up resource acquisition, reduce unnecessary network requests, and improve user experience. In frontend development, runtime caching strategy refers to how to effectively manage and use temporarily stored resources and data during browser runtime.
User requests resource
โ
โ
Check if resource exists in cache
โ
โโโ Yes: Read directly from cache (Cache Hit)
โ โโโ Return resource, save network request
โ
โโโ No: Request from remote server (Cache Miss)
โโโ Get resource โ Store in cache โ Return resourceBrowser Built-in Caching Mechanism
HTTP Cache
Browser's HTTP cache is the most basic and powerful caching mechanism, mainly controlled through HTTP headers.
Common Cache Control Headers:
Cache-Control: Set cache behavior
Expires: Set resource expiration time
ETag: Resource version identifier
Last-Modified: Resource last modification timeCache-Control Details
Cache-Control is the most important cache control header in HTTP/1.1, providing multiple directives:
| Directive | Description |
|---|---|
max-age | Resource is considered fresh within specified seconds, can use cache directly |
no-cache | Must first confirm with server if resource has been updated before using cache |
no-store | Never use cache, request new every time |
public | Response can be cached by any cache, including proxy servers |
private | Response can only be cached by browser, not by intermediate proxies |
must-revalidate | Must validate with origin server after expiration |
Difference between no-cache and no-store
no-cache
- 1. Not 'no caching', but 'no direct cache use'
- 2. Resources are stored in cache
- 3. Sends conditional request (using ETag or Last-Modified) to server to confirm if resource has been updated before use
- 4. If not updated, server returns 304 status code, browser uses cache
- 5. Suitable for: Content that changes frequently but remains unchanged most of the time (like news pages)
no-store
- 1. No caching at all
- 2. No responses are stored
- 3. Every request fetches complete resource from server
- 4. Suitable for: Sensitive information, continuously changing data (like real-time stock prices)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ no-cache vs no-store workflow โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ใFirst Requestใ
Browser Server
โ โ
โโโโ Request Resource โ>โ
โ โ
โ<โ Return Resource+Headers โโ
โ โ
ใSubsequent Request (no-cache)ใ
Browser Server
โ โ
โโ Conditional Request(with ETag) โ>โ
โ โ
โ<โโ 304 Not Modified โโ (Resource unchanged)
โ or 200 (Changed) โ
โ โ
ใSubsequent Request (no-store)ใ
Browser Server
โ โ
โโโโ Request Resource โ>โ
โ โ
โ<โ Return Full Resource โโ (Always returns full resource)
โ โETag Working Mechanism
ETag is a resource version identifier generated by the server, used to detect if a resource has changed:
- 1. Server returns ETag value with resource (usually a hash of the content)
- 2. When browser requests the same resource again, it sends
If-None-Matchheader with previously received ETag - 3. Server compares ETag:
- 1. If matches (resource unchanged): returns 304 status code, no entity content
- 2. If doesn't match (resource changed): returns 200 status code and complete resource, with new ETag
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ETag Workflow โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ใFirst Requestใ
Browser Server
โ โ
โโโโโโโโโโโ GET /image.jpg โโโโโโโโโโโ> โ
โ โ
โ<โโ HTTP/1.1 200 OK โ
โ ETag: "33a64df551425fcc55e4d42a" โ
โ (Image data...) โ
โ โ
ใSubsequent Requestใ
Browser Server
โ โ
โโโ GET /image.jpg โ
โ If-None-Match: "33a64df551425fcc55e4d42a" โ>โ
โ โ โโ Check ETag
โ โ โ matches
โ โ โ
โ<โโ HTTP/1.1 304 Not Modified โ Match!
โ ETag: "33a64df551425fcc55e4d42a" โ
โ (No entity content) โ
โ โ// Server-side cache header setting (Node.js Express example)
app.get('/api/data', (req, res) => {
// Set cache for one hour (3600 seconds)
res.setHeader('Cache-Control', 'max-age=3600');
res.json({ data: 'cached content' });
});
// Add cache control in frontend request
fetch('/api/user', {
cache: 'force-cache', // Force using cache
// Or use 'no-cache' for validation, 'no-store' for no caching
})Cache Control Strategy Diagram:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Cache Strategy Decision Flow โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Request Resource
โ
โ
Check Cache-Control
โ
โโโโโโโโโโโโโดโโโโโโโโโโโโ
โ โ
no-store exists Check other directives
(No caching at all) โ
โ โโโโโโโโโโโดโโโโโโโโโโ
โ โ โ
โ max-age not expired max-age expired
โ (Use cache directly) โ
โ โ โ
โ โ Has ETag/Last-Modified
โ โ โ
โ โ โ
โ โ Send conditional request to server
โ โ โ
โ โ โโโโโโโโโโดโโโโโโโโโ
โ โ โ โ
โ โ 304 Not Modified 200 Updated content
โ โ (Continue using cache) (Update cache and display)
โ โ โ โ
Make network Display Display Display new
request cached content cached content contentLocal Storage (Web Storage)
Besides HTTP caching, browsers also provide various local storage mechanisms for storing and caching data.
Web Storage Comparison Table
| Feature | localStorage | sessionStorage | IndexedDB | Cookies |
|---|---|---|---|---|
| Storage Capacity | ~5MB | ~5MB | Unlimited (depends on disk space) | ~4KB |
| Lifecycle | Permanent unless manually deleted | Deleted after page session ends | Permanent unless manually deleted | Can set expiration time |
| Data Types | String | String | Almost all JS data types, including binary | String |
| Use Cases | Persistent config, theme preferences | Form data temp storage, inter-page data transfer | Large structured data, offline apps | Authentication, tracking |
Web Storage Usage Examples
// localStorage basic operations
localStorage.setItem('theme', 'dark');
const theme = localStorage.getItem('theme');
localStorage.removeItem('theme');
// sessionStorage basic operations
sessionStorage.setItem('formData', JSON.stringify({ name: 'John' }));
const formData = JSON.parse(sessionStorage.getItem('formData'));
// Storage operations wrapper
class StorageUtil {
static set(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}
static get(key) {
const value = localStorage.getItem(key);
return value ? JSON.parse(value) : null;
}
static remove(key) {
localStorage.removeItem(key);
}
static clear() {
localStorage.clear();
}
}Important notes:
- 1. Web Storage can only store strings, use JSON.stringify() and JSON.parse() for complex data
- 2. Be aware of storage limits, use IndexedDB for large data
- 3. Don't store sensitive data locally as it can be accessed by attackers
IndexedDB
IndexedDB is a low-level API for client-side storage of significant amounts of structured data. It's a transactional database system, similar to SQL-based RDBMS.
IndexedDB Basic Usage
// Open database
const request = indexedDB.open('MyDatabase', 1);
// Handle database upgrade
request.onupgradeneeded = (event) => {
const db = event.target.result;
// Create object store (similar to table)
const store = db.createObjectStore('users', { keyPath: 'id' });
// Create index
store.createIndex('name', 'name', { unique: false });
};
// Database operations
request.onsuccess = (event) => {
const db = event.target.result;
// Write data
const transaction = db.transaction(['users'], 'readwrite');
const store = transaction.objectStore('users');
store.add({
id: 1,
name: 'John',
email: 'john@example.com'
});
// Read data
const getRequest = store.get(1);
getRequest.onsuccess = () => {
console.log(getRequest.result);
};
// Query using index
const nameIndex = store.index('name');
const nameQuery = nameIndex.get('John');
nameQuery.onsuccess = () => {
console.log(nameQuery.result);
};
};
// Error handling
request.onerror = (event) => {
console.error('Database error:', event.target.error);
};IndexedDB Use Cases
- 1. Offline application data storage: Save app data for offline functionality
- 2. Large files/binary data: Store images, audio, and other large files
- 3. Structured data queries: Data management requiring indexes and complex queries
- 4. Client-side caching: Cache API responses to improve app performance
Important Considerations
- 1. IndexedDB operations are asynchronous, handle callbacks properly or use Promise wrappers
- 2. Be aware of browser storage limits, usually a percentage of available disk space
- 3. Implement data synchronization mechanisms to ensure offline data can sync with the server
Data Request Caching Strategy (SWR)
SWR is a modern data fetching strategy that returns cached data first (stale), then sends a request to fetch the latest data (revalidate):
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ SWR (Stale-While-Revalidate) Request Flow โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Component Render
โ
โ
Check if data in cache
โ
โโโโโโโโโโโโโดโโโโโโโโโโโโ
โ โ
Has cached data No cached data
โ โ
โ โ
Return cached data Show loading state
โ โ
โ โ
โ โ
โโโโโโโโโโโโโฌโโโโโโโโโโโโ
โ
โ
Make network request for new data
โ
โโโโโโโโโโโโโดโโโโโโโโโโโโ
โ โ
Request success Request failed
โ โ
โ โ
Update cache data Show error state
โ
โ
Update UI with new data
Auto revalidation triggers:
- Window focus
- Network reconnection
- Timed refreshFrontend cache update is a common challenge, here are several solutions:
- 1. Use Version Numbers or Hash Values
<script src="app.3f8a7b9c.js"></script> <script src="app.js?v=1.2.3"></script> - 2. Set Appropriate Cache Control Headers
// HTML - ไธๅฟซๅๆๅฟซๅๆ้็ญ Cache-Control: no-cache, must-revalidate // CSS/JS - ้ทๆ้ๅฟซๅ๏ผไฝไฝฟ็จ็ๆฌๅURL Cache-Control: max-age=31536000, immutable - 3. Service Worker Version Management
// sw.js const CACHE_VERSION = 'v1.2.3'; const CACHE_NAME = `app-shell-${CACHE_VERSION}`; self.addEventListener('activate', event => { event.waitUntil( caches.keys().then(cacheNames => { return Promise.all( cacheNames .filter(name => name.startsWith('app-shell-')) .filter(name => name !== CACHE_NAME) .map(name => caches.delete(name)) ); }) ); }); - 4. API Data Refresh Strategy
// SWR Strategy: Show cached data first, then refresh in background function fetchData(url) { // Get data from cache and display immediately const cachedData = localStorage.getItem(url); if (cachedData) { renderData(JSON.parse(cachedData)); } // Simultaneously make new request to get latest data fetch(url) .then(res => res.json()) .then(newData => { // Update cache localStorage.setItem(url, JSON.stringify(newData)); // Update display renderData(newData); }); } - 5. Manual Force Update
// Provide manual refresh functionality for users function forceRefresh() { // Clear specific data cache localStorage.removeItem('user-data'); // Or reload page, bypassing cache location.reload(true); }
Practical Application Scenarios
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ E-commerce Product Page Caching Strategy โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
1. Static Resources (CSS/JS/Images)
โโโ HTTP Cache: Cache-Control: max-age=86400 (1 day)
โโโ Service Worker: Pre-cache core resources, offline support
2. Product Basic Info
โโโ localStorage: Recently viewed 20 products
โโโ SWR: Show cached data while revalidating in background
3. User Personalized Content (Cart/Favorites)
โโโ Short-term cache: Cache-Control: max-age=60 (1 minute)
4. Search Results/Recommendations
โโโ sessionStorage: Store search results for current session๐ฅ Common Interview Questions
1. What are the HTTP caching strategies? What are 'Strong Cache' and 'Negotiation Cache'?
Answer:
Strong Cache and Negotiation Cache are the two main mechanisms of HTTP caching:
Strong Cache
- 1. Use local cache directly, no server communication
- 2. Mainly controlled through
Cache-ControlandExpiresheaders - 3. Fastest response time, reduces server load
- 4. Example:
Cache-Control: max-age=3600(cache valid for 1 hour)
Negotiation Cache
- 1. Browser first asks server if resource has changed
- 2. Uses
ETagorLast-Modifiedheaders to negotiate with server - 3. If unchanged, server returns
304 Not Modified, browser uses local cache - 4. If changed, server returns
200 OKwith complete resource - 5. Example: Browser sends
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
2. Please explain the difference between no-cache and no-store in Cache-Control
Answer:
Practical Application Decision:
- 1. If data changes frequently but you still want to use cache to reduce server load: use
no-cache - 2. If data is very sensitive or must show latest data every time: use
no-store
3. How to implement offline functionality in frontend applications?
Answer:
Implementing offline functionality in frontend applications mainly relies on Service Worker and various storage APIs:
- 1. Service Worker Registration and Installation
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js') .then(reg => console.log('SW registered')) .catch(err => console.error('SW registration failed', err)); } - 2. Pre-cache Core Resources
// sw.js self.addEventListener('install', event => { event.waitUntil( caches.open('app-shell').then(cache => { return cache.addAll([ '/', '/index.html', '/styles.css', '/app.js', '/offline.html' ]); }) ); }); - 3. Offline Response Strategy
self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request) .then(response => { // Cache first, network as fallback return response || fetch(event.request) .then(response => { return caches.open('dynamic-content') .then(cache => { cache.put(event.request.url, response.clone()); return response; }); }) .catch(() => { // If it's a page request, return offline page if (event.request.mode === 'navigate') { return caches.match('/offline.html'); } }); }) ); }); - 4. Data Synchronization
// Use IndexedDB to store offline operations // Sync data when network is restored self.addEventListener('sync', event => { if (event.tag === 'sync-messages') { event.waitUntil(syncMessages()); } }); function syncMessages() { // Get messages stored offline and send to server return getMessagesFromIndexedDB() .then(messages => { return Promise.all(messages.map(msg => { return fetch('/api/messages', { method: 'POST', body: JSON.stringify(msg) }).then(() => { // Delete from IndexedDB after successful send return deleteMessageFromIndexedDB(msg.id); }); })); }); }
4. How to choose the appropriate frontend storage solution? What are their advantages and disadvantages?
Answer:
When choosing a frontend storage solution, consider data characteristics, usage scenarios, and security requirements:
1. Cookies
- 1. Advantages: Can set expiration time, automatically sent with requests to server
- 2. Disadvantages: Small capacity (about 4KB), increases network traffic, security concerns need careful handling
- 3. Use Cases: Authentication tokens, cross-page tracking
2. localStorage
- 1. Advantages: Permanent storage, cross-page sharing, larger capacity (~5MB), easy to use
- 2. Disadvantages: Synchronous operations may block UI, can only store strings, cannot set expiration time
- 3. Use Cases: User preferences, long-term application state
3. sessionStorage
- 1. Advantages: Valid during page session, persists after page reload, relatively secure
- 2. Disadvantages: Synchronous operations, can only store strings, cannot share between different pages
- 3. Use Cases: Form data temporary storage, single session state preservation
4. IndexedDB
- 1. Advantages: Large storage capacity, supports indexing and queries, asynchronous operations, transaction support
- 2. Disadvantages: Complex API, steep learning curve, limited support in older browsers
- 3. Use Cases: Large structured data storage, offline applications, complex data operations
5. Cache API
- 1. Advantages: Designed for HTTP requests/responses, can be used with Service Worker
- 2. Disadvantages: Mainly for HTTP caching, not for general data storage
- 3. Use Cases: Offline applications, PWA, resource caching
Decision Criteria:
- 1. Small amount and needs cross-request/authentication: Use Cookies
- 2. Simple configuration/UI state persistence: Use localStorage
- 3. Single session temporary data: Use sessionStorage
- 4. Large complex data or query capabilities needed: Use IndexedDB
- 5. Need offline work or resource caching: Use Cache API + Service Worker
Real applications often combine different storage methods: For example, offline applications might use IndexedDB (core data), localStorage (user settings), and Cache API (resource caching) simultaneously.
5. How to solve frontend cache update issues?
Answer:
Frontend cache update is a common challenge, here are several solutions:
- 1. Use Version Numbers or Hash Values
<script src="app.3f8a7b9c.js"></script> <script src="app.js?v=1.2.3"></script> - 2. Set Appropriate Cache Control Headers
// HTML - ไธๅฟซๅๆๅฟซๅๆ้็ญ Cache-Control: no-cache, must-revalidate // CSS/JS - ้ทๆ้ๅฟซๅ๏ผไฝไฝฟ็จ็ๆฌๅURL Cache-Control: max-age=31536000, immutable - 3. Service Worker Version Management
// sw.js const CACHE_VERSION = 'v1.2.3'; const CACHE_NAME = `app-shell-${CACHE_VERSION}`; self.addEventListener('activate', event => { event.waitUntil( caches.keys().then(cacheNames => { return Promise.all( cacheNames .filter(name => name.startsWith('app-shell-')) .filter(name => name !== CACHE_NAME) .map(name => caches.delete(name)) ); }) ); }); - 4. API Data Refresh Strategy
// SWR Strategy: Show cached data first, then refresh in background function fetchData(url) { // Get data from cache and display immediately const cachedData = localStorage.getItem(url); if (cachedData) { renderData(JSON.parse(cachedData)); } // Simultaneously make new request to get latest data fetch(url) .then(res => res.json()) .then(newData => { // Update cache localStorage.setItem(url, JSON.stringify(newData)); // Update display renderData(newData); }); } - 5. Manual Force Update
// Provide manual refresh functionality for users function forceRefresh() { // Clear specific data cache localStorage.removeItem('user-data'); // Or reload page, bypassing cache location.reload(true); }