挖掘可观察量的计算会炸毁计算时间

时间:2014-02-26 17:15:05

标签: javascript performance knockout.js observable

当我用ko observables做一些繁重的计算时,我注意到了一个问题。

您可以在http://jsfiddle.net/dundanox/AyU8y/1/

找到问题的示例

为了保持简短,我有一个输入字段和一个可观察的“val”

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

现在,有两种方法可以更改observable的值 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;

这似乎取决于我如何设置observable的值。为什么会这样?我该如何解决?

3 个答案:

答案 0 :(得分:0)

当你输入它时,它是一个字符串,字符串操作比数字

使用parseFloat

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

结果也是错误的,将字符串和数字相结合不是一回事

答案 1 :(得分:0)

安德斯是对的!操作更昂贵,因为javascript需要在每次迭代时进行隐式类型转换。也许你听说过===运算符,因为它比较了类型和值,不同于==运算符,它只比较了值,但对你要比较的值进行了隐式类型转换。 / p>

希望它有所帮助!

答案 2 :(得分:0)

问题的根本原因是当敲除通知输入的值更改时,它会从输入字段中读取新值并将其写回observable。

输入的值是一个字符串,这就是KO放入observable的内容。

如果您希望它是一个数字,那么您需要始终将值强制转换为数字。这样做的最佳方式(恕我直言)是通过 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;
}

创建我们的observable使用以下

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

现在,当设置了observable的值时,无论您是使用数字类型手动执行,还是使用字符串通过元素更改事件进行淘汰,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));