简体   繁体   中英

Using a promise in Aurelia for data retrieval and caching

I've created a data service that gets data sets from an API, but I'd like to have it first cache it locally and check if the same data is already available (nevermind the stale data factor... I'll deal with that next). Here's my code:

getData(url, use_cache = true) {
  // Http Fetch Client to retreive data (GET)
  let cache_index = this.cache.findIndex(r => { return r.url === url; });
  if ((use_cache) && (cache_index > -1) && (this.cache[cache_index].data.length)) {
    // Use cached data (available)
    console.log("Found cached data!", this.cache[cache_index].data);
    //
    // I think this next line is the problem... need to return a promise???
    //
    return this.cache[cache_index].data;
  } else {
    console.log("Retrieving records from " + url);
    return this.httpClient.fetch(url, {
      credentials: 'include'
    }).then(response => {
      // Old statement was simple...
      // return response.json();

      // New method seems to be working because it's saving the data into the cache
      return response.json().then(result => {
        this.cache.push({'url': url, 'data': result});
        // Not sure why I need this next line, but I do.
        return result;
      });
    });
  }
}

It works fine to retrieve the data the first time, and even on the second call I can see (from the console log) that it finds the correct cached data, but I'm getting an error that I believe is related to promises, which is not in my area of expertise yet.

Error message: ERROR [app-router] TypeError: this.core.getData(...).then is not a function

This error is actually in my viewmodel's caller, which looks like this:

getAccounts() {
  this.core.getData('/accounting/account/all').then(response => {
    this.accounts = response;
  });
}

I guess since when the data is cached, instead of returning a promise it's actually returning the data, and there's no .then method on the raw data.

I suspect I need to either create a fake promise (even though it's not an async transaction) to return when the data is cached or improve the way I'm calling this method from my data service (or returning the data).

Any ideas on how to fix this current problem? Any free advice on this whole topic as it relates to Aurelia?

I guess since when the data is cached, instead of returning a promise it's actually returning the data, and there's no .then method on the raw data.

Yes.

I suspect I need to either create a fake promise (even though it's not an async transaction) to return when the data is cached

Possible (using Promise.resolve ), but no.

…or improve the way I'm calling this method from my data service (or returning the data).

No, for sure you shouldn't need that.

Instead, there's a much simpler solution: cache the promise object itself, and return the same promise from every call for that url!

getData(url, use_cache = true) {
  // Http Fetch Client to retreive data (GET)
  if (use_cache && url in this.cache)
    return this.cache[url];
  else
    return this.cache[url] = this.httpClient.fetch(url, {
      credentials: 'include'
    }).then(response => response.json());
}

This has the additional benefit that you'll never have two parallel requests for the same resource - the request itself is cached, not only the arrived result. The only drawback is that you also cache errors, if you want to avoid that and retry on subsequent calls then you have to drop the cache on rejections.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM