【问题标题】:calculations with knockout observables blows up calculation time使用剔除可观察量的计算会增加计算时间
【发布时间】:2014-03-29 16:51:15
【问题描述】:

当我对 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 的值。为什么会这样?我该如何解决?

【问题讨论】:

    标签: javascript performance knockout.js observable


    【解决方案1】:

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

    使用parseFloat

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

    结果也是错误的,拼接字符串和数字不是一回事

    【讨论】:

      【解决方案2】:

      安德斯是对的!该操作更昂贵,因为 javascript 需要在每次迭代时进行隐式类型转换。也许您听说过 === 运算符,因为它比较类型和值,所以推荐使用它,这与 == 运算符不同,后者只比较值,但对您正在比较的值进行隐式类型转换。

      希望对你有帮助!

      【讨论】:

        【解决方案3】:

        您的问题的根本原因是,当敲除收到输入值更改的通知时,它会从输入字段中读取新值并将其写回可观察对象。

        输入的值是一个字符串,所以这就是 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));
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-25
          • 1970-01-01
          相关资源
          最近更新 更多