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

JS应用中仅缓存WMTS服务getCapabilities响应的重复请求问题

问题分析与解决方案

核心问题

你碰到的两个关键问题:

  1. Map缓存被重复初始化:如果承载缓存的模块被多次加载(比如打包配置问题、不同路径重复导入),每个模块实例都会创建新的Map,导致缓存完全失效。
  2. 并发请求竞态:第一次请求还在处理时,第二次调用检查缓存发现为空,会重复发起相同请求。

修复方案

1. 确保缓存是单例

ES模块默认是单例,但如果项目存在重复导入场景,建议把缓存抽成独立模块,彻底保证单例:

// cache.js
export const capabilitiesCache = new Map();

然后在你的函数模块中导入:

import { capabilitiesCache } from './cache.js';

2. 缓存Promise避免并发重复请求

原代码只缓存最终解析结果,并发场景下会重复发起请求。改为缓存请求的Promise,让后续调用直接等待同一个请求完成:

import { capabilitiesCache } from './cache.js';

export async function getCapabilities(layer, capabilitiesTimeout) {
  const libFetch = require('whatwg-fetch').fetch;
  const view = layer.views[0];
  if (!view) throw new Error('图层无可用视图配置');
  
  const { baseUrl, serviceType, serviceVersion } = view;
  // 用完整请求参数作为缓存键,避免不同参数的请求共用缓存
  const cacheKey = `${baseUrl}?SERVICE=${serviceType}&REQUEST=GetCapabilities&VERSION=${serviceVersion}`;

  // 缓存存在则直接返回(可能是pending的Promise或已完成的结果)
  if (capabilitiesCache.has(cacheKey)) {
    return capabilitiesCache.get(cacheKey);
  }

  const url = new URL(baseUrl);
  url.searchParams.append('SERVICE', serviceType);
  url.searchParams.append('REQUEST', 'GetCapabilities');
  url.searchParams.append('VERSION', serviceVersion);

  // 创建请求Promise并缓存
  const requestPromise = (async () => {
    try {
      const response = await timeout(capabilitiesTimeout, fetch(getProxiedUrl(url)));
      const text = await response.text();

      let parsedResponse;
      if (serviceType === TYPE_WMTS) {
        parsedResponse = parser.read(text);
      } else if (serviceType === TYPE_WMS) {
        parsedResponse = parserWms.read(text);
      }

      return parsedResponse;
    } catch (e) {
      console.warn(
        `'GetCapabilities' 超时(${capabilitiesTimeout}ms),图层:"${layer?.title}"`,
        e
      );
      // 出错时移除缓存,避免后续调用直接获取错误Promise
      capabilitiesCache.delete(cacheKey);
      throw e;
    }
  })();

  capabilitiesCache.set(cacheKey, requestPromise);
  return requestPromise;
}

3. 可选:其他缓存方案

如果需要更复杂的缓存策略,比如过期时间、容量限制,可以考虑:

  • LRU缓存:使用lru-cache库,设置最大缓存数量和过期时间,自动淘汰不常用的缓存。
  • 持久化缓存:用localStorage/sessionStorage存储序列化后的响应,但注意只能存储字符串,需要处理解析/序列化逻辑,适合跨会话缓存场景。

内容的提问来源于stack exchange,提问作者cam_gis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 15:26:23