GeminiWorkflow 中的 IndexedDB 图片缓存实践

GeminiWorkflow 中的 IndexedDB 图片缓存实践

_

在 GeminiWorkflow 项目中,我们使用 IndexedDB 在浏览器本地缓存宫格图、分镜图等大尺寸 Base64 图片数据,显著减少重复网络请求,并为复杂工作流提供稳定、高性能的本地缓存能力。

本文将从技术选型、数据库设计、核心 API、智能更新机制以及工程实践经验几个维度,完整介绍这一套 IndexedDB 缓存方案。


一、背景与目标

在 GeminiWorkflow 的实际使用过程中,存在以下特点:

  • 图片体积大(Base64,单张可达数 MB)

  • 图片复用率高(反复查看历史任务)

  • 用户频繁在同一会话内切换任务

  • 网络请求成本高,影响交互体验

如果每次都从服务器拉取图片,会带来明显的性能问题。

核心目标

  • 减少重复请求

  • 提升页面响应速度

  • 支持长期本地缓存

  • 具备自动更新与清理能力


二、为什么选择 IndexedDB?

在浏览器端缓存方案中,IndexedDB 与 localStorage 的对比如下:

特性

IndexedDB

localStorage

存储容量

可达磁盘空间的 ~50%(通常数百 MB)

约 5–10 MB

数据类型

对象、数组、Blob、二进制

仅字符串

API 形式

异步

同步(阻塞主线程)

查询能力

支持索引与条件查询

适用场景

大文件、结构化数据

简单键值对

结论很明确:

当缓存对象是“大体量、结构化数据”时,IndexedDB 是浏览器端的唯一合理选择。


三、数据库架构设计

3.1 数据库基础配置

文件位置:src/utils/imageCache.js

const DB_NAME = 'GeminiWorkflowCache';
const DB_VERSION = 1;
const STORE_NAME = 'images';
  • 单一数据库,集中管理图片缓存

  • 使用版本号支持后续结构升级


3.2 对象存储(Object Store)结构

images Store 中的每条记录结构如下:

字段

类型

说明

key

String

主键:{type}:{clientId}:{taskId}

type

String

缓存类型:grid / splits

clientId

String

客户端唯一标识

taskId

String

任务 ID

data

Object

图片数据(Base64)

timestamp

Number

缓存时间

expiry

Number

过期时间

size

Number

数据大小(MB)

etag

String | null

数据指纹

version

String | null

服务端版本号

lastModified

String | null

最后修改时间

这种设计可以同时满足:

  • 精准定位缓存

  • 版本比对

  • 后期统计与清理


3.3 索引设计

store.createIndex('timestamp', 'timestamp', { unique: false });
store.createIndex('expiry', 'expiry', { unique: false });
store.createIndex('size', 'size', { unique: false });

索引的主要用途:

  • 快速清理过期缓存

  • 统计缓存大小

  • 支持后台扫描与维护任务


四、核心 API 设计

4.1 ImageCache 核心类

ImageCache 以单例模式导出:

export const imageCache = new ImageCache();

核心方法一览

方法

说明

init

初始化数据库

saveImage

保存图片缓存

getImage

获取缓存

deleteImage

删除指定缓存

cleanExpired

清理过期缓存

clearAll

清空缓存

getCacheSize

获取缓存总大小

getAllCacheMeta

获取缓存元数据


4.2 基本使用示例

import { imageCache } from '@/utils/imageCache';

// 保存宫格图
await imageCache.saveImage(
  'grid',
  clientId,
  taskId,
  { grid_image: 'data:image/png;base64,...' }
);

// 获取宫格图
const cached = await imageCache.getImage('grid', clientId, taskId);

五、智能缓存更新系统

单纯的缓存并不足够,缓存必须“可控、可更新”

因此在项目中引入了智能缓存更新机制


5.1 更新流程说明

核心思路:

  1. 周期性获取服务器任务元数据

  2. 对比本地缓存版本

  3. 找出版本不一致的缓存

  4. 并发更新对应图片

流程示意如下:

服务器元数据
      ↓
本地缓存版本对比
      ↓
筛选需要更新的缓存
      ↓
限制并发批量更新

5.2 启动智能更新

位置:src/App.jsx

import { startSmartCacheUpdate } from './utils/imageCache';

const stopUpdate = startSmartCacheUpdate(
  getHistoryMeta,
  getTaskGridImage,
  getTaskSplitImages,
  clientId,
  5 * 60 * 1000
);
  • 默认每 5 分钟 执行一次

  • 并发数量限制为 3,防止阻塞主线程


六、API 层的缓存优先策略

缓存并不是独立存在的,而是深度集成在 API 层

6.1 缓存优先流程

export async function getTaskGridImage(taskId, clientId) {
  // 1. 尝试读取缓存
  const cached = await imageCache.getImage('grid', clientId, taskId);
  if (cached) {
    return { ...cached, _fromCache: true };
  }

  // 2. 请求服务器
  const response = await fetchWithRetry(url);

  // 3. 写入缓存
  await imageCache.saveImage(
    'grid',
    clientId,
    taskId,
    response,
    task.updated_at
  );

  return { ...response, _fromCache: false };
}

特点:

  • 缓存失败不影响主流程

  • 接口返回中明确标识是否来自缓存

  • 对业务层完全透明


6.2 缓存 Key 规范

类型

Key 格式

宫格图

grid:{clientId}:{taskId}

分镜图

splits:{clientId}:{taskId}

统一规范便于调试和维护。


七、调试与运维工具

为方便开发和排查问题,项目内置了完整的缓存调试工具。

7.1 控制台调试 API

CacheDebug.stats();           // 缓存统计
CacheDebug.getAll();          // 所有缓存项
CacheDebug.inspect(...);      // 单条缓存详情
CacheDebug.compare(...);      // 与服务器对比
CacheDebug.clear();           // 清空缓存
CacheDebug.clean();           // 清理过期缓存

7.2 直接查看 IndexedDB

const request = indexedDB.open('GeminiWorkflowCache', 1);
request.onsuccess = () => {
  const db = request.result;
  const tx = db.transaction(['images'], 'readonly');
  const store = tx.objectStore('images');
  store.getAll().onsuccess = e => console.log(e.target.result);
};

八、缓存配置策略

const CACHE_CONFIG = {
  DEFAULT_EXPIRY: 7 * 24 * 60 * 60 * 1000, // 7 天
  MAX_CACHE_SIZE: 100,                    // 100 MB
  FORCE_REFRESH_INTERVAL: 24 * 60 * 60 * 1000
};

自动维护机制

  • 每 10 分钟清理过期缓存

  • 每 5 分钟执行智能更新

  • 超出最大容量自动回收旧数据


九、工程实践经验总结

9.1 缓存不应阻塞业务

try {
  await imageCache.saveImage(...);
} catch (err) {
  console.error('缓存失败,不影响主流程', err);
}

缓存永远是增强能力,而非依赖点


9.2 防止重复请求

  • 内部维护 pendingRequests Map

  • 相同请求复用进行中的 Promise


9.3 后台验证机制

  • 命中缓存时立即返回

  • 后台异步校验服务器版本

  • 保证下次访问数据最新


十、结语

在 GeminiWorkflow 中,IndexedDB 不再只是“本地存储”,而是:

一个 具备版本控制、容量管理、自动更新能力的前端缓存系统

这套方案在保证数据一致性的同时,大幅提升了复杂工作流场景下的用户体验,也为后续的离线能力和 PWA 演进奠定了基础。

Git 同时推送到多个远程仓库(阿里云效 + GitHub) 2026-02-12
Nginx 常用命令大全 2026-02-03

评论区