You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 22:40:38