JavaScript中API调用结果的优雅缓存方案咨询
优雅解决API查询结果缓存的问题
针对你遇到的查询参数属性顺序不同导致缓存失效的问题,这里有几个实用的解决方案:
方案1:排序对象属性后再序列化
核心思路是先将查询对象的属性按固定顺序(比如字母序)排序,再生成JSON字符串,这样不管原对象属性顺序如何,序列化结果都一致。
可以封装一个工具函数来处理:
function getSortedQueryKey(query: Record<string, any>): string { // 提取所有键并按字母排序 const sortedKeys = Object.keys(query).sort(); // 按排序后的键重新构建对象 const sortedQuery = sortedKeys.reduce((acc, key) => { acc[key] = query[key]; return acc; }, {} as Record<string, any>); // 序列化排序后的对象 return JSON.stringify(sortedQuery); } // 改造后的缓存函数 const CACHE = new Map<string, Promise<any>>(); async function getItemList(query: {itemType: string; region: string | undefined; /* 其他参数 */}) { const cacheKey = getSortedQueryKey(query); if (CACHE.has(cacheKey)) { return CACHE.get(cacheKey); } const requestPromise = client.get('/path/to/api', query); CACHE.set(cacheKey, requestPromise); // 可选:处理请求失败后移除缓存,避免缓存错误结果 requestPromise.catch(() => { CACHE.delete(cacheKey); }); return requestPromise; }
这里用Map替代普通对象作为缓存容器,比对象更安全(避免键名冲突),同时缓存Promise可以解决并发请求重复调用API的问题。
方案2:按固定参数顺序手动构建缓存键
如果查询参数的字段是固定的,可以直接按预先定义的顺序拼接参数值,这样完全不用依赖JSON序列化:
const CACHE = new Map<string, Promise<any>>(); async function getItemList(query: {itemType: string; region: string | undefined; /* 其他参数 */}) { // 按固定顺序拼接,注意处理undefined的情况 const cacheKey = [ query.itemType, query.region ?? 'undefined', // 依次添加其他固定参数,比如query.page ?? 1等 ].join('|'); // 用特殊分隔符避免参数值拼接后混淆 if (CACHE.has(cacheKey)) { return CACHE.get(cacheKey); } const requestPromise = client.get('/path/to/api', query); CACHE.set(cacheKey, requestPromise); requestPromise.catch(() => CACHE.delete(cacheKey)); return requestPromise; }
这种方式性能更好,也更直观,适合参数字段固定的场景。
方案3:使用memoize工具(带自定义缓存键生成器)
如果不想自己写缓存逻辑,可以用lodash.memoize(需要安装lodash),自定义缓存键的生成逻辑:
import { memoize } from 'lodash'; // 先定义生成排序后键的函数 function createCacheKey(query: {itemType: string; region: string | undefined; /* 其他参数 */}) { const sortedKeys = Object.keys(query).sort(); return JSON.stringify(sortedKeys.map(key => [key, query[key]])); } // 用memoize包装API函数 const getItemList = memoize( (query) => client.get('/path/to/api', query), createCacheKey );
lodash的memoize会自动处理缓存逻辑,你只需要提供正确的缓存键生成函数即可。
额外注意点
- 缓存清理:如果后续有需求需要清空缓存(比如数据更新后),可以给缓存容器(比如Map)加一个清空方法,或者用lodash.memoize的
memoize.Cache自定义缓存存储。 - 处理特殊值:比如
undefined、null、空字符串等,要统一处理方式,避免因为值的表现形式不同导致缓存键不一致。
内容的提问来源于stack exchange,提问作者ilu
相关产品推荐
相关产品推荐

