BRUCE_FEBRUCE_FE

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.

ๅฝฑ็‰‡็ธฎๅœ–

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 resource

Browser 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 time

Cache-Control Details

Cache-Control is the most important cache control header in HTTP/1.1, providing multiple directives:

DirectiveDescription
max-ageResource is considered fresh within specified seconds, can use cache directly
no-cacheMust first confirm with server if resource has been updated before using cache
no-storeNever use cache, request new every time
publicResponse can be cached by any cache, including proxy servers
privateResponse can only be cached by browser, not by intermediate proxies
must-revalidateMust 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. 1. Server returns ETag value with resource (usually a hash of the content)
  2. 2. When browser requests the same resource again, it sends If-None-Match header with previously received ETag
  3. 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)                   โ”‚
   โ”‚                                          โ”‚
Cache Control Examples:
// 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    content

Local Storage (Web Storage)

Besides HTTP caching, browsers also provide various local storage mechanisms for storing and caching data.

Web Storage Comparison Table

FeaturelocalStoragesessionStorageIndexedDBCookies
Storage Capacity~5MB~5MBUnlimited (depends on disk space)~4KB
LifecyclePermanent unless manually deletedDeleted after page session endsPermanent unless manually deletedCan set expiration time
Data TypesStringStringAlmost all JS data types, including binaryString
Use CasesPersistent config, theme preferencesForm data temp storage, inter-page data transferLarge structured data, offline appsAuthentication, 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 refresh
How to solve frontend cache update issues?

Frontend cache update is a common challenge, here are several solutions:

  1. 1. Use Version Numbers or Hash Values
    <script src="app.3f8a7b9c.js"></script>
    
    <script src="app.js?v=1.2.3"></script>
  2. 2. Set Appropriate Cache Control Headers
    // HTML - ไธๅฟซๅ–ๆˆ–ๅฟซๅ–ๆ™‚้–“็Ÿญ
    Cache-Control: no-cache, must-revalidate
    
    // CSS/JS - ้•ทๆ™‚้–“ๅฟซๅ–๏ผŒไฝ†ไฝฟ็”จ็‰ˆๆœฌๅŒ–URL
    Cache-Control: max-age=31536000, immutable
  3. 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. 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. 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-Control and Expires headers
  • 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 ETag or Last-Modified headers to negotiate with server
  • 3. If unchanged, server returns 304 Not Modified, browser uses local cache
  • 4. If changed, server returns 200 OK with 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. 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. 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. 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. 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. 1. Use Version Numbers or Hash Values
    <script src="app.3f8a7b9c.js"></script>
    
    <script src="app.js?v=1.2.3"></script>
  2. 2. Set Appropriate Cache Control Headers
    // HTML - ไธๅฟซๅ–ๆˆ–ๅฟซๅ–ๆ™‚้–“็Ÿญ
    Cache-Control: no-cache, must-revalidate
    
    // CSS/JS - ้•ทๆ™‚้–“ๅฟซๅ–๏ผŒไฝ†ไฝฟ็”จ็‰ˆๆœฌๅŒ–URL
    Cache-Control: max-age=31536000, immutable
  3. 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. 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. 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);
    }