Javascript 如何优化KnockoutJS pureComputed函数?
我开始注意到我的小游戏表现不佳,因为我在游戏中加入了更多的KO元素 我有一个ResourcesVM,它包含所有Resources作为一个可观察的数组。此存储MainResource对象包含名称、总数量、总容量,以及用于存储此Resource的所有Building对象的列表 示例:岩石和木材在其“仓库建筑”中都有相同的库存建筑对象。此Ressource对象存储在RessourcesVM的AllResources observableArray中 我正在尝试创建一个显示资源数量的小中心 在我的mainResource对象中,我有一个pureComputed函数要计算,我决定在这里解析整个对象,以便您更好地理解该对象:Javascript 如何优化KnockoutJS pureComputed函数?,javascript,performance,knockout.js,Javascript,Performance,Knockout.js,我开始注意到我的小游戏表现不佳,因为我在游戏中加入了更多的KO元素 我有一个ResourcesVM,它包含所有Resources作为一个可观察的数组。此存储MainResource对象包含名称、总数量、总容量,以及用于存储此Resource的所有Building对象的列表 示例:岩石和木材在其“仓库建筑”中都有相同的库存建筑对象。此Ressource对象存储在RessourcesVM的AllResources observableArray中 我正在尝试创建一个显示资源数量的小中心 在我的mai
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;
});
}
函数MainResource(数据){
var self=这个;
self.Name=data.Name;
self.IconCss=data.IconCss;
//建筑施工完成后,由BuildingVM递增
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(函数(){
var p=Game.app.cf.refreshEvery/self.ProductionRate();
如果(p>0&&p!=“无穷大”)
返回p;
返回0;
});
如果(data.StoredIn){//TODO正确实现此操作
self.StoredIn=data.StoredIn;
}否则{
console.log(“警告:名为“+self.name+”的Ressource似乎没有设置StoredIn。”);
}
self.StorageBuildings=ko.observearray([]);
自产建筑=ko.observearray([]);
self.OccupyingSpace=ko.可观察(data.OccupyingSpace);
self.getMaxCapacity=ko.pureComputed(函数(){
如果(self.Name==“能量”){
//能量不会“储存”在任何建筑物中,而是直接返回值
var v=数学层(self.TotalCapacity());
}else if(self.Name==“Wood”){
//要计算最大木材承载力,请删除岩石占用的空间
var r=Game.app.Ressources.AllRessources()[2];
r=(r.TotalQte()/r.OccupyingSpace());
var v=数学层((self.TotalCapacity()-r)/self.OccupyingSpace());
}else if(self.Name==“Rock”){
//要计算最大木材容量,请删除木材占用的空间
var w=Game.app.resources.allresources()[1];
w=(w.TotalQte()/w.OccupyingSpace());
var v=数学层((self.TotalCapacity()-w)/self.OccupyingSpace());
}else if(self.StoredIn==“食品仓库”){
var startWith=self.TotalCapacity();//总食物容量
//对于存储在FoodStorage building type中的每个Ressource,请删除该Ressource的占用空间
对于(var l=Game.app.resources.allresources.length,i=0;i
我知道pureComputed函数目前有点混乱,我仍在努力找出最好的方法
我应该在RessourcesVM中移动getMaxCapacity函数吗?这会给我带来一些性能优势吗
有关逻辑的更多信息:
你可以有多个库存,库存存储木材和岩石。岩石使用2个空格,木材使用1个空格(这就是为什么在前面的代码中存在“占用空间”的原因)
你可以有多个粮仓,粮仓里有苹果和面包
我需要知道所有粮仓中有多少苹果,以及所有粮仓的总容量
谢谢你的帮助
edit在我的解释中将Ressource更改为MainRessource,以反映代码中提供的真实对象的名称。我不确定您的确切性能问题是什么,但您可以尝试将计算结果扩展为
.extend({deferred:true})
。这确保了当您连续修改其依赖项时,您的计算结果只重新评估一次。(例如,将n
次推到AllResources
会导致1
计算)。谢谢,我确保我的pureComputed“正常”“,以前从未使用过KO,我觉得这个函数太大了。但是的,我已经设置了KO.options.deferUpdates=false;KO.options.rateLimit=25;
;)thxI仍然认为您可以改进计算方法,但我认为您不必太担心性能。改进要点:由于Name
不可见,我建议使用iLife来确保Mainif
语句只执行一次。很好,非常感谢!
<!-- 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 -->