Storing KnockoutJS modeled data with AmplifyJS

2019-08-15 22:08发布

问题:

I'm trying to figure out a way to cache my knockoutJS SPA data and I've been experimenting with amplifyJS. Here's one of my GET functions:

UserController.prototype.getUsers = function() {
   var self = this;

   return $.ajax({
      type: 'GET',
      url: self.Config.api + 'users'
   }).done(function(data) {
      self.usersArr(ko.utils.arrayMap(data.users, function(item) {
         // run each item through model
         return new self.Model.User(item);
      }));         
   }).fail(function(data) {
      // failed
   });
};

Here's the same function, "amplified":

UserController.prototype.getUsers = function() {
   var self = this;

   if (amplify.store('users')) {
      self.usersArr(ko.utils.arrayMap(amplify.store('users'), function(item) {
         // run each item through model
         return new self.Model.User(item);
      }));
  } else {
     return $.ajax({
        type: 'GET',
        url: self.Config.api + 'users'
     }).done(function(data) {
        self.usersArr(ko.utils.arrayMap(data.users, function(item) {
           // run each item through model
           return new self.Model.User(item);
        }));         
     }).fail(function(data) {
      // failed
   });
};

This works as expected, but I'm not sure about the approach I used, because it will also require extra work on the addUser, removeUser and editUser functions. And seeing as I have many more similar functions throughout my app, I'd like to avoid the extra code if possible.

I've found a way of handling things with the help of ko.extenders, like so:

this.usersArr = ko.observableArray().extend({ localStore: 'users'  });

Then use the ko.extenders.localStore function to update the local storage data whenever it detects a change inside the observableArray. So on init it will write to the observableArray in case local storage data exists for users key and on changes it will update the local storage data.

My problem with this approach is that I need to run my data through the model and I couldn't find a way to do that from the localStore function, which is kept on a separate page.

Has any of you worked with KO and Amplify? What approach did you use? Should I use the first one or try a combination of the two and rewrite the extender in a way that it only updates the local storage without writing to the observableArray on init?

回答1:

Following the discussion in the question's comments, I suggested to use native HTTP caching instead of adding another caching layer on the client by means of an extra library.

This would require implementing a conditional request scheme.

Such a scheme relies on freshness information in the Ajax response headers via the Last-Modified (or E-Tag) HTTP headers and other headers that influence browser caching (like Cache-Control: with its various options).

  • The browser transparently sends an If-Modified-Since (or If-None-Match) header to the server when the same resource (URL) is requested subsequently.

  • The server can respond with HTTP 304 Not Modified if the client's information is still up-to-date. This can be a lot faster than re-creating a full response from scratch.

  • From the Ajax request's point of view (jQuery or otherwise) a response works the same way, no matter if it actually came from the server or if it came from the browser's cache, the latter is only a lot faster.

Carefully adapting the server side is necessary for this, the client side on the other hand does not need much change.

The benefit of implementing conditional requests is reduced load on the server and faster response behavior on the client.

A specialty of Knockout to improve this even further:

If you happen to use the mapping plugin to map raw server data to a complex view model, you can define - as part of the options that control the mapping process - a key function. Its purpose is to match parts of your view model against parts of the source data.

This way parts of the data that already have been mapped will not be mapped again, the others are updated. That can help reduce the client's processing time for data it already has and, potentially, unnecessary screen updates as well.