imetting/design/meeting-cache-usage.md

5.1 KiB

会议缓存服务使用指南

概述

meetingCacheService 是一个独立的缓存服务,用于缓存会议列表的查询结果,减少不必要的网络请求,提升用户体验。

导入

import meetingCacheService from '../services/meetingCacheService';

核心API

1. 生成过滤器键

const filterKey = meetingCacheService.generateFilterKey(
  filterType,    // 'all' | 'created' | 'attended'
  searchQuery,   // 搜索关键词字符串
  selectedTags   // 标签数组 ['tag1', 'tag2']
);

2. 获取缓存数据

获取单页缓存

const cachedPage = meetingCacheService.getPage(filterKey, pageNumber);
// 返回: { meetings: [...], pagination: {...} } 或 null

获取所有页缓存

const allCached = meetingCacheService.getAllPages(filterKey);
// 返回: { pages: { 1: {...}, 2: {...} }, timestamp: number } 或 null

3. 设置缓存

meetingCacheService.setPage(
  filterKey,
  pageNumber,
  meetingsArray,
  paginationObject
);

4. 清除缓存

清除所有缓存

meetingCacheService.clearAll();

清除特定过滤器

meetingCacheService.clearFilter(filterKey);

清除匹配模式的缓存

// 清除所有包含 'created' 的过滤器缓存
meetingCacheService.clearPattern('created');

5. 检查缓存状态

检查过滤器是否存在

const hasFilter = meetingCacheService.hasFilter(filterKey);
// 返回: boolean

检查特定页是否存在

const hasPage = meetingCacheService.hasPage(filterKey, pageNumber);
// 返回: boolean

6. 获取统计信息

const stats = meetingCacheService.getStats();
// 返回: {
//   filterCount: number,   // 缓存的过滤器数量
//   totalPages: number,    // 总页数
//   totalMeetings: number, // 总会议数
//   cacheSize: number      // 估算大小(KB)
// }

使用示例

完整的数据获取流程

const fetchMeetings = async (page = 1, isLoadMore = false) => {
  try {
    // 1. 生成过滤器键
    const filterKey = meetingCacheService.generateFilterKey(
      filterType,
      searchQuery,
      selectedTags
    );

    // 2. 检查缓存
    if (!isLoadMore) {
      // 新查询,检查第一页缓存
      const allCached = meetingCacheService.getAllPages(filterKey);
      if (allCached && allCached.pages[1]) {
        console.log('Using cached data');
        setMeetings(allCached.pages[1].meetings);
        setPagination(allCached.pages[1].pagination);
        return;
      }
    } else {
      // 加载更多,检查该页缓存
      const cachedPage = meetingCacheService.getPage(filterKey, page);
      if (cachedPage) {
        console.log('Using cached page:', page);
        setMeetings(prev => [...prev, ...cachedPage.meetings]);
        setPagination(cachedPage.pagination);
        return;
      }
    }

    // 3. 没有缓存,从服务器获取
    setLoading(true);
    const response = await apiClient.get('/api/meetings', { params });

    // 4. 缓存数据
    meetingCacheService.setPage(
      filterKey,
      page,
      response.data.meetings,
      response.data.pagination
    );

    // 5. 更新UI
    if (isLoadMore) {
      setMeetings(prev => [...prev, ...response.data.meetings]);
    } else {
      setMeetings(response.data.meetings);
    }
    setPagination(response.data.pagination);

  } catch (err) {
    console.error('Error:', err);
  } finally {
    setLoading(false);
  }
};

数据变更时清除缓存

const handleDeleteMeeting = async (meetingId) => {
  await apiClient.delete(`/api/meetings/${meetingId}`);

  // 清除所有缓存
  meetingCacheService.clearAll();

  // 重新加载数据
  await fetchMeetings(1, false);
};

缓存策略

缓存时间

  • TTL: 5分钟
  • 超过5分钟的缓存会自动失效并被清除

缓存结构

{
  "filterKey1": {
    pages: {
      1: { meetings: [...], pagination: {...} },
      2: { meetings: [...], pagination: {...} }
    },
    timestamp: 1234567890
  },
  "filterKey2": {
    ...
  }
}

过滤器键格式

格式: filterType|searchQuery|tags 示例:

  • all|| - 全部会议,无搜索,无标签
  • created|| - 我创建的会议
  • all|meeting|tag1,tag2 - 全部会议,搜索"meeting",标签"tag1,tag2"

调试工具

在开发环境下,控制台会自动注册调试命令:

// 查看缓存统计
window.meetingCache.stats()

// 查看详细信息
window.meetingCache.info()

// 清除所有缓存
window.meetingCache.clear()

最佳实践

  1. 及时清除缓存: 数据变更(增删改)后立即清除相关缓存
  2. 合理使用: 只缓存频繁访问的数据
  3. 监控缓存大小: 定期检查缓存占用情况
  4. 错误处理: 缓存失败时应该降级到正常的网络请求

性能优势

  • 减少网络请求: 相同查询直接从内存读取
  • 即时响应: 缓存命中时响应 < 10ms
  • 降低服务器负载: 减少重复查询
  • 提升用户体验: 无刷新切换过滤条件