2014-02-26 26 views
1

當我使用ko觀測值進行一些繁重的計算時,我發現了一個問題。敲除觀測數據的計算會導致計算時間變長

問題的一個例子,你會發現在http://jsfiddle.net/dundanox/AyU8y/1/

爲了簡化我有一個輸入字段和一個可觀察的「VAL」

<input data-bind="value: val"> 

現在,有更改值兩種方法的可觀察的。
1.在手動輸入字段
2.鍵入一個(新)的值由腳本分配一個(新)的值,例如ViewModel.val(3.14)

設定值後,我做一些繁重的計算,例如

var val = ViewModel.val(); // get current value, e.g. 3.14 

for(var sum=0, ii=0; ii > imax; ii++) 
    sum += val 

如果我通過腳本(第二種方法)設置值,一切都很好。 但是,如果我手動設置一個值(第一種方法),計算時間會多次爆炸!

我認爲這是奇怪的行爲,不應該是。但我找不到問題。這是knockoutJS內的問題嗎?

爲了澄清它,用下面的代碼一切都很好。

var val = 3.14; 

for(var sum=0, ii=0; ii > imax; ii++) 
    sum += val 

我行

var val = ViewModel.val(); // get current value, e.g. 3.14 

的理解應該是一樣的,如果我寫

var val = 3.14; 

看來這取決於如何設置的可觀察的價值。爲什麼是這樣?我該如何解決它?

回答

0

當你鍵入這是一個字符串,字符串操作比數量更慢

使用parseFloat

http://jsfiddle.net/AyU8y/2/

結果也是錯誤的,concating字符串和數字是不一樣的東西

0

安德斯是對的!該操作更昂貴,因爲JavaScript需要在每次迭代中進行隱式類型轉換。也許你聽說過===運算符,這是推薦的,因爲它比較了類型和值,與==運算符不同,後者僅比較值,但對所比較的值進行隱式類型轉換。

希望它有幫助!

0

你的問題的根本原因是,當淘汰賽被告知輸入的值變化的讀取從輸入字段的新值,並寫道,回觀測。

輸入的值是一個字符串,所以這就是KO是置於觀察到。

如果你希望它是一個數字,那麼你將需要始終如一強制值轉換成數字。最好的辦法(恕我直言)這樣做是通過擴展點fn

ko.observable.fn['asNumber'] = function (defaultValue) { 
    var target = this; 
    var interceptor = ko.computed({ 
     read: target, 
     write: function (value) { 
      var parsed = parseFloat(value); 
      var manualNotifyFlag = false; 
      if (isNaN(parsed)) { 
       parsed = defaultValue; 
       manualNotifyFlag = (target() === parsed); 
      } 

      if (!manualNotifyFlag) { 
       target(parsed); 
      } else { 
       target.valueHasMutated(); 
      } 
     } 
    }); 

    interceptor(target()); // Ensure target is properly initialised. 
    return interceptor; 
} 

創造我們觀察到使用下列

val: ko.observable(3.14).asNumber(0) 

現在,當觀察到的值設置,無論你做手工使用數量型,或敲除通過元素使用字符串改變事件,observable的值將被強制爲一個數字。

這使您不必將parseFloats放到您的代碼庫中。

我已更新fiddle以顯示此項。

此外,在擴展parseFloat語句可以很容易地被改造,以支持任何全球化引擎,再次只在你的代碼庫來做到這一點在同一個地方

// Using the jQuery Globalize library from http://github.com/jquery/globalize 
var parsed = (typeof (value) === "string" ? 
    Globalize.parseFloat(value) : 
    parseFloat(value));