2014-05-16 120 views
1

我有一個淘汰賽應用程序,我有可寫的已計算觀測量的層次結構像下面的性能問題:有很多淘汰賽嵌套寫computeds

function InvoiceVM() { 
    self.isSelected = ko.observable() 
    self.selectedAmount = ko.computed(function() { 
     if (self.isSelected()) 
      return self.usdBalance; 
     else 
      return 0; 
    } 
} 
function CompanyVM() { 
    self.invoices = ko.observableArray() 
    self.totalSelectedAmount = ko.computed(function() { 
     var total = 0; 
     for (var i = 0; i < self.invoices().length; i++) { 
      total += self.invoices()[i].selectedAmount(); 
     } 
     return total; 
    }); 

    self.isSelected = ko.computed({ 
     read: function() { 
      var isSelected = true; 
      for (var i = 0; i < self.invoices().length; i++) { 
       if (!self.invoices()[i].isSelected()) 
        isSelected = false; 
      } 
      return isSelected; 
     }, 
     write: function (value) { 
      for (var i = 0; i < self.invoices().length; i++) 
       self.invoices()[i].isSelected(value); 
     }, 
     deferEvaluation: true, 
     owner: self 
    }) 
} 
function ParentVM() { 
    self.companies = ko.observableArray() 
    self.isSelected = ko.computed({ 
     read: function() { 
      var isSelected = true; 
      for (var i = 0; i < self.funds().length; i++) { 
       if (!self.companies()[i].isSelected()) { 
        isSelected = false; 
        break; 
       } 
      } 
      return isSelected; 
     }, 
     write: function (value) { 
      for (var i = 0; i < self.companies().length; i++) { 
       var currentCompany = self.companies()[i]; 
       for (var j = 0; j < currentCompany.invoices().length; j++) 
        currentCompany.invoices()[j].isSelected(value); 
      } 

     }, 

     deferEvaluation: true 
    }); 
} 

的問題是,當parentVM選擇(通過複選框)需要30-40秒才能渲染所有複選框並更新總金額。大約有4500個發票和大約274家公司(但只有公司正在展示,發票隱藏使用display:none)。我嘗試使用延遲更新插件限制觀察對象,無論是否使用deferEvaluation選項,都通過jQuery手動選擇複選框(這不適用於雙向綁定)。有沒有人有關於加速這個過程的建議?在此先感謝您的幫助!

+0

考慮切換模板引擎。 –

+0

另外,您可以修改底層數組和批量更改,然後手動通知更改(如​​果有幫助)。 –

+0

你推薦什麼模板引擎? – mets19

回答

2

一看,我注意到幾件事情:

  • 在WR由於您正在更新依賴於read函數的值,因此您在更新每個isSelected時都會觸發計算結果。您可以使用油門(或3.1中的rateLimit)擴展器來確保讀取功能不會繼續被調用。

  • 在您的read函數中,只要您發現錯誤值,您就可以真正退出。在這種情況下,您不需要遍歷所有的值。

  • totalSelectedAmount也得到重新計算時,每個isSelected得到更新。這對throttle/rateLimit也是一個不錯的選擇。

就這麼說,仍然有很多數據需要同步更新。對於setTimeout中的每個公司(或大部分公司)更新isSelected以確保瀏覽器在整個處理期間不被凍結是值得的。

下面是一個包含以下許多變化的示例:http://jsfiddle.net/rniemeyer/k4vJ8/。我可能會考慮在每次setTimeout上更新大量公司,而不是每次更新一次。

+0

感謝您的幫助!分批做更新對我有用。 – mets19

1

加快速度的一種方法是在底層數組ko.observableArray上運行操作。例如,您可以如果你的ko.observableArray包含大量元素(這你所做的),那麼這樣做肯定會淨您顯著的速度提升改變這種

for (var i = 0; i < self.invoices().length; i++) 
     self.invoices()[i].isSelected(value); 

這個

var underlying = self.invoices(); 
for (var i = 0; i < underlying.length; i++) 
     underlying[i].isSelected(value); 

self.invoices.valueHasMutated(); 

。您發佈的代碼中有多處可以實現此目的。有關更多信息,請參閱Knockout.js Performance Gotcha #2 - Manipulating observableArrays