阿里云主机折上折
  • 微信号
Current Site:Index > Data caching strategy

Data caching strategy

Author:Chuan Chen 阅读数:12686人阅读 分类: ECharts

Basic Concepts of Data Caching Strategies

The core of data caching strategies lies in reducing redundant computations and network requests to improve data access efficiency. As a visualization library, ECharts frequently handles dynamic data updates and interactive operations. A well-designed caching mechanism can significantly optimize performance. Common scenarios include high-frequency chart redraws, large-scale data rendering, and asynchronous data loading.

In-Memory Cache Implementation Methods

ECharts can store processed data in memory objects to avoid repeated parsing. For example, using WeakMap to store series data and their corresponding rendering results:

const renderCache = new WeakMap();

function getCachedRender(series) {
  if (!renderCache.has(series)) {
    const renderResult = heavyCompute(series.data);
    renderCache.set(series, renderResult);
  }
  return renderCache.get(series);
}

For time-series data, an LRU caching strategy can be employed:

class TimeSeriesCache {
  constructor(maxSize = 100) {
    this.cache = new Map();
    this.maxSize = maxSize;
  }

  get(key) {
    if (!this.cache.has(key)) return null;
    const value = this.cache.get(key);
    // Refresh access time
    this.cache.delete(key);
    this.cache.set(key, value);
    return value;
  }

  set(key, value) {
    if (this.cache.size >= this.maxSize) {
      // Remove the least recently used
      const oldestKey = this.cache.keys().next().value;
      this.cache.delete(oldestKey);
    }
    this.cache.set(key, value);
  }
}

Local Storage Caching Solutions

For configuration data that requires persistence, localStorage can be utilized:

const CACHE_KEY = 'echarts_config_cache';

function saveConfigToCache(config) {
  try {
    const serialized = JSON.stringify({
      timestamp: Date.now(),
      data: config
    });
    localStorage.setItem(CACHE_KEY, serialized);
  } catch (e) {
    console.warn('LocalStorage quota exceeded');
  }
}

function loadConfigFromCache() {
  const cached = localStorage.getItem(CACHE_KEY);
  if (!cached) return null;
  
  try {
    const parsed = JSON.parse(cached);
    // Validate cache expiration (example: 24-hour expiry)
    if (Date.now() - parsed.timestamp > 86400000) {
      localStorage.removeItem(CACHE_KEY);
      return null;
    }
    return parsed.data;
  } catch {
    return null;
  }
}

Data Chunking Caching Techniques

For ultra-large datasets, chunked loading and caching can be employed:

class DataChunkManager {
  constructor(chunkSize = 10000) {
    this.chunkSize = chunkSize;
    this.chunkCache = new Map();
  }

  async loadChunk(dataset, chunkIndex) {
    const cacheKey = `${dataset.id}_${chunkIndex}`;
    
    if (this.chunkCache.has(cacheKey)) {
      return this.chunkCache.get(cacheKey);
    }

    const start = chunkIndex * this.chunkSize;
    const end = start + this.chunkSize;
    const chunkData = await fetchChunk(dataset.url, start, end);
    
    this.chunkCache.set(cacheKey, chunkData);
    return chunkData;
  }
}

Cache Invalidation Mechanism Design

Effective invalidation strategies are crucial for caching systems. Common approaches in ECharts include:

  1. Version-based validation:
function checkDataVersion(current, cached) {
  return current.version === cached?.metadata?.version;
}
  1. Visualization parameter change detection:
function paramsChanged(currentOpts, cachedOpts) {
  const keys = ['xAxis', 'yAxis', 'series'];
  return keys.some(key => 
    !shallowEqual(currentOpts[key], cachedOpts[key])
  );
}
  1. Hybrid invalidation strategy example:
class SmartCache {
  constructor() {
    this.dataCache = new Map();
    this.renderCache = new Map();
  }

  shouldInvalidate(dataId, renderOpts) {
    const cachedData = this.dataCache.get(dataId);
    const cachedRender = this.renderCache.get(dataId);
    
    return !cachedData || 
           !cachedRender ||
           dataChanged(cachedData.checksum, currentData) ||
           renderOptsChanged(cachedRender.params, renderOpts);
  }
}

Performance Optimization Case Studies

A real-time monitoring system implemented a three-tier caching architecture:

  1. In-memory hot data cache (last 5 minutes of data):
const liveDataCache = {
  _data: [],
  maxAge: 300000, // 5 minutes
  
  push(newPoint) {
    this._data.push({
      timestamp: Date.now(),
      value: newPoint
    });
    this.cleanup();
  },

  cleanup() {
    const cutoff = Date.now() - this.maxAge;
    this._data = this._data.filter(item => item.timestamp > cutoff);
  },

  get() {
    this.cleanup();
    return this._data.map(item => item.value);
  }
};
  1. IndexedDB historical data cache:
const dbPromise = new Promise(resolve => {
  const request = indexedDB.open('EChartsHistoryDB', 1);
  
  request.onupgradeneeded = (e) => {
    const db = e.target.result;
    if (!db.objectStoreNames.contains('history')) {
      db.createObjectStore('history', { keyPath: 'timeRange' });
    }
  };

  request.onsuccess = (e) => resolve(e.target.result);
});

async function queryHistory(start, end) {
  const db = await dbPromise;
  const tx = db.transaction('history', 'readonly');
  const store = tx.objectStore('history');
  
  return new Promise(resolve => {
    const request = store.get(`${start}-${end}`);
    request.onsuccess = () => resolve(request.result?.data || null);
  });
}
  1. Server-side cache negotiation:
async function fetchDataWithCache(url) {
  const cached = sessionStorage.getItem(`api:${url}`);
  const headers = {};
  
  if (cached) {
    const { etag } = JSON.parse(cached);
    headers['If-None-Match'] = etag;
  }

  const response = await fetch(url, { headers });
  
  if (response.status === 304) {
    return JSON.parse(cached).data;
  }

  const newData = await response.json();
  sessionStorage.setItem(`api:${url}`, JSON.stringify({
    etag: response.headers.get('ETag'),
    data: newData
  }));
  
  return newData;
}

Special Scenario Handling Solutions

Tree Data Caching

class TreeDataCache {
  constructor() {
    this.nodeMap = new Map();
  }

  cacheNode(path, node) {
    this.nodeMap.set(path.join('/'), {
      data: node,
      lastUsed: Date.now()
    });
  }

  getNode(path) {
    const key = path.join('/');
    if (this.nodeMap.has(key)) {
      const entry = this.nodeMap.get(key);
      entry.lastUsed = Date.now();
      return entry.data;
    }
    return null;
  }
}

Geographic Coordinate Data Optimization

const geoCoordCache = new Proxy({}, {
  get(target, property) {
    if (!(property in target)) {
      target[property] = echarts.getMap(property);
    }
    return target[property];
  }
});

// Usage example
function renderMap(chart, mapName) {
  const geoJson = geoCoordCache[mapName];
  chart.setOption({
    geo: {
      map: mapName,
      type: 'map',
      ...
    }
  });
}

Cache Monitoring and Debugging

During development, monitoring logic can be injected:

class CacheTracker {
  constructor() {
    this.hits = 0;
    this.misses = 0;
  }

  track(condition) {
    condition ? this.hits++ : this.misses++;
    
    if ((this.hits + this.misses) % 100 === 0) {
      console.log(`Cache hit rate: ${this.hits/(this.hits+this.misses)*100}%`);
    }
  }
}

const renderCacheTracker = new CacheTracker();

function cachedRender(data) {
  const cached = getFromCache(data.id);
  renderCacheTracker.track(!!cached);
  
  return cached || computeRender(data);
}

In production environments, the Performance API can be used for measurement:

function measureCachePerformance() {
  const mark = name => performance.mark(`cache_${name}`);
  const measure = (name, start, end) => {
    performance.measure(name, start, end);
    return performance.getEntriesByName(name).pop();
  };

  mark('start_uncached');
  renderWithoutCache();
  mark('end_uncached');
  
  mark('start_cached');
  renderWithCache();
  mark('end_cached');

  const uncached = measure('uncached', 'start_uncached', 'end_uncached');
  const cached = measure('cached', 'start_cached', 'end_cached');

  console.log(`Performance improvement: ${(uncached.duration - cached.duration).toFixed(2)}ms`);
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:数据异常处理

下一篇:数据安全考虑

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.