How can I optimize my KnockoutJS pureComputed func

2019-08-16 08:17发布

问题:

I'm starting to notice poor performance in my little game as I'm adding more KO stuff to it.

I have a RessourcesVM which contain AllRessources as an observableArray. This store MainRessource object containing the name, total quantity, total capacity, a list of all Building object that is used to store this ressource.

Example: Rock and Wood have both the same Stockpile Building object in their "StorageBuilding". This Ressource object is stored in RessourcesVM's AllRessources observableArray.

I'm trying to create a little HUB that display the number of ressources.

In my MainRessource object I have this pureComputed function to calculate, I decided the parse the whole object here so you get a better understanding of the object:

function MainRessource(data) {
  var self = this;

  self.Name = data.Name;
  self.IconCss = data.IconCss;

  //Incremented by the BuildingVM once the building's construction is completed
  self.TotalQte = ko.observable(isNaN(data.TotalQte) ? 0 : data.TotalQte);
  self.TotalCapacity = ko.observable(isNaN(data.TotalCapacity) ? 0 : data.TotalCapacity);


  self.ProductionRate = ko.observable(isNaN(data.ProductionRate) ? 0 : data.ProductionRate);
  self.getProductionRatePerSecond = ko.pureComputed(function() {
    var p = Game.app.cf.refreshEvery/self.ProductionRate();
    if(p > 0 && p != 'Infinity')
      return p;
    return 0;
  });

  if(data.StoredIn) { //TODO implement this properly
    self.StoredIn = data.StoredIn;
  } else {
    console.log("Warning: Ressource with name "+self.Name+" doesn't appear to have a StoredIn set.");
  }
  self.StorageBuildings = ko.observableArray([]);
  self.ProductionBuildings = ko.observableArray([]);

  self.OccupyingSpace = ko.observable(data.OccupyingSpace);


    self.getMaxCapacity = ko.pureComputed(function() {

      if(self.Name == "Energy") {
        //Energy is not "stored" in any buildings, return direct value
        var v = Math.floor(self.TotalCapacity());

      } else if(self.Name == "Wood") {
        //To calculate max wood capacity,, remove the space Rock occupies
        var r = Game.app.Ressources.AllRessources()[2];
        r = (r.TotalQte() / r.OccupyingSpace());

        var v = Math.floor((self.TotalCapacity()-r)/self.OccupyingSpace());

      } else if(self.Name == "Rock") {
        //To calculate max wood capacity,, remove the space Wood occupies
        var w = Game.app.Ressources.AllRessources()[1];
        w = (w.TotalQte() / w.OccupyingSpace());

        var v = Math.floor((self.TotalCapacity()-w)/self.OccupyingSpace());

      } else if(self.StoredIn == "FoodStorage") {
        var startWith = self.TotalCapacity(); //Total food capacity
        //For each Ressource that is stored in FoodStorage building type, remove the occupying space of that ressource
        for(var l = Game.app.Ressources.AllRessources.length, i = 0; i < l; i++) {
            //Skip the ressource we are calculating for
            if(Game.app.Ressources.AllRessources.StoredIn == 'FoodStorage' && Game.app.Ressources.AllRessources.Name != self.Name) {
              var w = Game.app.Ressources.AllRessources()[i];
              startWith -= (w.TotalQte() / w.OccupyingSpace());
            }
          }

          var v = Math.floor(startWith/self.OccupyingSpace());
      }

      if(isNaN(v) || v <= 0)
        return 0;

      return v;
    });

}

The HTML code for the HUB looks like this:

<!-- ko with: Ressources -->
  <!-- ko foreach: AllRessources -->
  <div class="hub" >
    <i data-bind="css: IconCss"></i>
    <span data-bind="text: Math.floor(TotalQte())"></span>/<span data-bind="text: getMaxCapacity()"></span>
    (<span data-bind="text: getProductionRatePerSecond()"></span>) <span data-bind="meter: {value: TotalQte, max: TotalCapacity }" class="meter-sm"></span>
  </div>
  <!-- /ko -->
<!-- /ko -->

I know the pureComputed function is a little mess for now, I'm still trying to figure out the best way to do this.

Should I move the getMaxCapacity function in the RessourcesVM? Would this give me some performance benefits?

More infos about the logic: You can have multiple stockpiles, stockpiles stores Wood and Rock. Rock use 2 spaces, wood use 1 (That's why there is this "OccupyingSpace thing in the previous code) You can have multiple Granaries, Granaries stores Apple and Bread.

I need to know how many Apples there is across all Granaries and the combined capacity of all granaries.

Thanks for your help

edit changed Ressource to MainRessource in my explanation to reflect the real object's name provided in the code.