skip to Main Content

In my JS app, I’m trying to cache the getCapabilities responses for my WMTS services only.

I have this function, but when the function is called twice with the exact same baseUrl in the layer object, the request is sent twice anyway.

It does look like the Map object is being reinitialized in between calls though. I tried to add a global counter to the function and at every call, the counter was stuck to 0.

I’m also willing to try other caching solutions than Map.

Here’s my code :

const cache = new Map()

export async function getCapabilities(layer, capabilitiesTimeout) {
  const libFetch = require('whatwg-fetch').fetch;
  const url = new URL(layer.views[0]?.baseUrl);
  const cachedRequestId = layer.views[0]?.baseUrl;

  if (!cache.get(cachedRequestId)) {
    const version = layer.views[0].serviceVersion;
    url.searchParams.append('SERVICE', layer.views[0].serviceType);
    url.searchParams.append('REQUEST', 'GetCapabilities');
    url.searchParams.append('VERSION', version);
  
    let response;
    let parsedResponse;
  
    try {
      response = await timeout(capabilitiesTimeout, fetch(getProxiedUrl(url)));
      const text = await response.text();
  
      if (layer.views[0].serviceType === TYPE_WMTS) {
        parsedResponse = parser.read(text);
        cache.set(cachedRequestId, parsedResponse);
      } else if (layer.views[0].serviceType === TYPE_WMS) {
        parsedResponse = parserWms.read(text);
      }
  
      return parsedResponse;
    } catch (e) {
      console.warn(
        `'GetCapabilities' timeout (${capabilitiesTimeout}ms) for layer "${
          layer?.title
        }"`,
        e
      );
    }
  }
  return cache.get(cachedRequestId)
}

2

Answers


  1. If the Map instance is getting reinitialised; you can use the Singleton design pattern to ensure that the cache is only created once and shared across all instances of your function.

    You can create a function that returns the same instance of the cache every time it is called.

    // singletonMap.js file
    let cache;
    
    export default function getCacheInstance() {
      if (!cache) {
        cache = new Map();
      }
      return cache;
    }
    

    which you can use in your getCapabilities function:

    import getCacheInstance from './singletonMap';
    
    export async function getCapabilities(layer, capabilitiesTimeout) {
      const cache = getCacheInstance();
      ...
    }
    
    Login or Signup to reply.
  2. It does look like the Map object is being reinitialized in between calls though

    No, it’s not. Rather the problem is that …

    when the function is called twice with the exact same baseUrl in the layer object, the request is sent twice anyway

    … because you are not storing anything in the cache until the response is received. So while the first request is still under way, the second call to getCapabilities will see an empty cache and make its own request.

    The solution to this problem is to cache the promise itself, immediately when the first call is made.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search