расчеты с нокаутирующими наблюдаемыми увеличивают время расчета

Я заметил проблему, когда выполняю тяжелые вычисления с ko observables.

Пример проблемы вы найдете на 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;

Кажется, это зависит от того, как я устанавливаю значение наблюдаемого. Почему это так? И как я могу это исправить?


person user3356865    schedule 26.02.2014    source источник


Ответы (3)


Когда вы вводите его, это строка, операция со строкой выполняется медленнее, чем с числом.

используйте 1_

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

Результат тоже неверный, объединение строк и чисел — не одно и то же.

person Anders    schedule 26.02.2014

Андерс прав! операция стоит дороже, потому что javascript должен выполнять неявное приведение типов на каждой итерации. Возможно, вы слышали об операторе ===, который рекомендуется, поскольку он сравнивает и тип, и значение, в отличие от оператора ==, который сравнивает только значение, но выполняет неявное приведение типов к сравниваемым значениям.

Надеюсь, поможет!

person Juan Fausd    schedule 26.02.2014

Основная причина вашей проблемы заключается в том, что когда нокаут уведомляется об изменении значения ввода, он считывает новое значение из поля ввода и записывает его обратно в наблюдаемое.

Входное значение представляет собой строку, так что это то, что 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)

Теперь, когда значение наблюдаемого установлено, независимо от того, делаете ли вы это вручную, используя числовой тип, или выбиваете через событие изменения элементов, используя строку, значение наблюдаемого будет принудительно преобразовано в числовое.

Это избавляет вас от использования parseFloats по всей кодовой базе.

Я обновил скрипту, чтобы показать это.

Кроме того, оператор parseFloat в расширении можно легко модифицировать для поддержки любого механизма глобализации, опять же, для этого нужно сделать это только в одном месте в кодовой базе.

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