vue3-ref-kv-cache
v0.1.0
Published
A Vue 3 key-value cache utility with reactive bindings, TTL, persistence, and request deduplication.
Readme
vue3-ref-kv-cache
一个面向 Vue 3 的响应式键值缓存工具库,适合把异步请求结果缓存成可复用的 ref 状态,并支持:
- 同 key 并发请求去重
- TTL 过期控制
localStorage持久化use()组合式调用get()/refresh()/peek()/remove()/clear()/cleanExpired()
这个仓库用于源码开发、测试和本地调试;npm 包发布时只包含构建产物和必要说明文件,不包含 src、demo、tests 等开发目录。
安装
npm install vue3-ref-kv-cache vue要求:
- Vue 版本:
^3.3.0 - 包格式:同时提供 ESM、CJS 和 TypeScript 类型声明
快速开始
import { createKvCache } from 'vue3-ref-kv-cache';
interface User {
id: number;
name: string;
}
const userCache = createKvCache<User, { userId: number }>({
ttl: 5_000,
query: async ({ userId }) => {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
throw new Error('获取用户信息失败');
}
return response.json();
},
});
const userState = userCache.use({ userId: 1 });
console.log(userState.loading.value);
console.log(userState.status.value);
console.log(userState.data.value);
console.log(userState.error.value);在 Vue 组件里可以直接使用:
<script setup lang="ts">
import { createKvCache } from 'vue3-ref-kv-cache';
interface User {
id: number;
name: string;
}
const userCache = createKvCache<User, { userId: number }>({
ttl: 10_000,
query: async ({ userId }) => {
const response = await fetch(`/api/users/${userId}`);
return response.json();
},
});
const user = userCache.use({ userId: 1 });
</script>
<template>
<div v-if="user.loading.value">加载中...</div>
<div v-else-if="user.error.value">请求失败</div>
<pre v-else>{{ user.data.value }}</pre>
</template>持久化缓存
const articleCache = createKvCache({
ttl: 60_000,
persist: true,
storageKey: 'article-cache',
query: async ({ slug }: { slug: string }) => {
const response = await fetch(`/api/articles/${slug}`);
if (!response.ok) {
throw new Error('获取文章失败');
}
return response.json();
},
});说明:
- 只有成功请求到的数据会写入
localStorage - 持久化内容会在新实例创建时自动恢复
- 已过期数据会在恢复阶段自动清理
- 在不支持
localStorage的环境中会自动降级,不会阻塞库本身运行
自定义缓存 key
默认情况下,库会对参数做稳定序列化,所以这两次调用会命中同一个缓存:
cache.get({ userId: 1, tab: 'profile' });
cache.get({ tab: 'profile', userId: 1 });如果你的参数里包含不适合序列化的内容,或者你想自己控制 key,可以传入 getKey:
const cache = createKvCache({
getKey: (params: { userId: number }) => `user:${params.userId}`,
query: async ({ userId }) => {
const response = await fetch(`/api/users/${userId}`);
return response.json();
},
});建议:
- 参数尽量使用普通对象、数组、字符串、数字等稳定结构
- 如果参数里存在循环引用,请务必自己传
getKey
API
createKvCache<TData, TParams>(options)
import type { KvCacheController } from 'vue3-ref-kv-cache';
function createKvCache<TData, TParams>(
options: CreateKvCacheOptions<TData, TParams>,
): KvCacheController<TData, TParams>;options
| 参数 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| query | (params: TParams) => Promise<TData> | 必填 | 实际请求函数 |
| ttl | number | 0 | 缓存有效期,单位毫秒;0 表示不过期 |
| persist | boolean | false | 是否启用 localStorage 持久化 |
| storageKey | string | vue3-ref-kv-cache | 持久化存储 key |
| getKey | (params: TParams) => string | 内置稳定序列化 | 自定义缓存 key 生成逻辑 |
返回值
返回一个缓存控制器对象:
use(params)get(params)refresh(params)peek(params)remove(params)clear()cleanExpired()
use(params)
立即返回响应式状态,并在有需要时自动触发请求。
const state = cache.use({ id: 1 });返回结构:
{
data: Ref<TData | undefined>;
loading: Ref<boolean>;
error: Ref<unknown>;
status: Ref<'idle' | 'loading' | 'success' | 'error'>;
refresh: () => Promise<TData>;
remove: () => void;
}说明:
- 首次调用时会自动请求
- 如果同一个 key 已有进行中的请求,会复用该请求
- 如果缓存仍有效,会直接复用缓存值
refresh()会忽略当前缓存并强制重新请求
get(params)
获取缓存值;如果缓存不存在或已过期,则发起请求并返回结果。
const data = await cache.get({ id: 1 });适合:
- 组合式函数外部使用
- 需要直接拿到 Promise 结果的场景
- 服务方法、事件处理器、手动预加载场景
refresh(params)
忽略当前缓存,强制重新请求并更新缓存。
await cache.refresh({ id: 1 });peek(params)
只读取当前缓存快照,不会触发请求。
const snapshot = cache.peek({ id: 1 });返回结构:
{
key: string;
data: TData | undefined;
error: unknown;
status: 'idle' | 'loading' | 'success' | 'error';
loading: boolean;
expireAt: number;
updatedAt: number;
isExpired: boolean;
}适合:
- 调试和排查缓存状态
- 在不希望触发请求时读取当前缓存
- 做一些额外的 UI 展示或日志记录
remove(params)
删除指定 key 的缓存。
cache.remove({ id: 1 });clear()
清空当前缓存实例下的所有缓存。
cache.clear();cleanExpired()
清理当前实例中已经过期的缓存项。
cache.cleanExpired();缓存行为说明
1. 同 key 并发去重
同一个 key 在请求进行中时,后续 get() / use() / refresh() 会复用当前 Promise,不会重复请求。
2. 过期策略
ttl = 0:永不过期ttl > 0:请求成功时记录过期时间,超过后下一次读取会重新请求
3. 错误处理
- 请求失败后,
status会变为error - 失败不会被当作成功结果缓存
- 同一个 key 后续再次调用时会重新请求
4. 持久化策略
- 只持久化成功数据
- 不持久化
loading这类运行时状态 - 已过期或非法数据会在恢复时自动清理
本地调试
仓库内置了一个 Vite 示例页,专门用于调试缓存行为。
启动方式:
pnpm install
pnpm dev示例页可调试的内容包括:
use()/get()/refresh()/peek()- TTL 过期行为
localStorage持久化恢复- 模拟接口延迟
- 模拟下一次请求失败
remove()/clear()/cleanExpired()
调试页面源码位于仓库中的 demo/App.vue。
开发与测试
pnpm build
pnpm test
pnpm typecheck
pnpm pack:check说明:
build:使用tsup生成disttest:运行vitesttypecheck:运行vue-tscpack:check:使用npm pack --dry-run检查最终发包内容
发布说明
当前发布策略是“仓库里保留源码开发,npm 只发构建结果”。
最终 npm 包只包含:
distREADME.mdLICENSE- npm 自动带入的
package.json
不会包含:
srcdemotestsvite.config.tstsup.config.ts- 其他开发配置文件
建议发布前执行:
pnpm build
pnpm test
pnpm typecheck
pnpm pack:check
npm publish