В чем разница на ko.computed между deferEvaluation и extend({deferred: true})

Меня немного смущает объяснение поведения отложенного вычисления, определенного в переменной ko.computed.

Такая вычисляемая переменная может быть определена со свойством deferEvaluation: true, которое должно отложить оценку до момента, когда любое другое свойство запросит значение переменной (см. http://knockoutjs.com/documentation/Computed-reference.html),

Когда обычная переменная ko.computed расширяется с помощью extend({deferred: true}), она вызывает расчет асинхронно и откладывает его до тех пор, пока все запущенные в данный момент «потоки» не закончатся (см. http://Knockoutjs.com/documentation/deferred-updates.html).

Эти две настройки звучат очень похоже, но каждая из них делает что-то совершенно другое.

Может ли кто-нибудь подтвердить мне, что я прав, или объяснить разницу, если я ошибаюсь?


person Jan Stanicek    schedule 31.01.2017    source источник


Ответы (2)


deferEvaluation касается только отсрочки первоначальной оценки. Обычно, когда вы создаете вычисляемый объект, его оценщик вызывается прямо тогда, синхронно, что означает (среди прочего), что все наблюдаемые, от которых он зависит, уже должны быть инициализированы. Использование deferEvaluation предотвращает это и делает первый вызов вычисляемой функции вычислителя в первый раз, когда что-либо подписывается на вычисляемое (или никогда, если ничего не происходит). После этого он больше не действует; вычисляемый по-прежнему переоценивается каждый раз, когда что-либо зависит от изменений, немедленно.

.extend({deferred: true}) заключается в том, чтобы всегда откладывать выполнение оценщика до тех пор, пока не завершится задача, создавшая или изменившая его (и затем, как правило, до следующего обновления пользовательского интерфейса). Речь идет не только о первоначальной оценке, это означает, что каждый раз, когда вычисляемые наблюдаемые зависят от изменения, эти изменения могут устанавливаться, делая вычисляемую оценку асинхронной (после текущей задачи) и ожидая их стабилизации.

Вот фрагмент, показывающий использование ни одного из них, использование deferEvaluation и использование .extend({deferred: true}). Обратите внимание на различия в том, когда вызываются оценщики.

setTimeout(function() {
  console.log("---- Using neither:");
  var ob1 = ko.observable(10);
  console.log("creating c1");
  var c1 = ko.computed(function() {
    console.log("c1 evaluated");
    return ob1() * 2;
  });
  console.log("Setting ob1 to 20");
  ob1(20);
  console.log("subscribing to c1");
  c1.subscribe(function(newValue) {
    console.log("c1's new value is " + newValue);
  });
  console.log("Setting ob1 to 30");
  ob1(30);
  console.log("Setting ob1 to 40");
  ob1(40);
}, 50);

setTimeout(function() {
  console.log("---- Using .extend({deferEvaluation: true}):");
  var ob2 = ko.observable(10);
  console.log("creating c2");
  var c2 = ko.computed(function() {
    console.log("c2 evaluated");
    return ob2() * 2;
  }, null, { deferEvaluation: true });
  console.log("Setting ob2 to 20");
  ob2(20);
  console.log("subscribing to c2");
  c2.subscribe(function(newValue) {
    console.log("c2's new value is " + newValue);
  });
  console.log("Setting ob2 to 30");
  ob2(30);
  console.log("Setting ob2 to 40");
  ob2(40);
}, 200);

setTimeout(function() {
  console.log("---- Using .extend({deferred: true}):");
  var ob3 = ko.observable(10);
  console.log("creating c3");
  var c3 = ko.computed(function() {
    console.log("c3 evaluated");
    return ob3() * 2;
  }).extend({ deferred: true });
  console.log("Setting ob3 to 20");
  ob3(20);
  console.log("subscribing to c3");
  c3.subscribe(function(newValue) {
    console.log("c3's new value is " + newValue);
  });
  console.log("Setting ob3 to 30");
  ob3(30);
  console.log("Setting ob3 to 40");
  ob3(40);
}, 400);
.as-console-wrapper {
  max-height: 100% !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>

person T.J. Crowder    schedule 31.01.2017

deferEvaluation предотвратит вычисление от определения его начального значения (и зависимостей), пока что-то действительно не получит к нему доступ. Это может быть программно (доступ к вычисляемому коду) или через привязку. Это может быть полезно для сценариев «курица и яйцо», когда вычисляемый код должен ждать, пока другие вещи будут настроены перед запуском, или для эффективности, если вычисляемый код будет запускаться несколько раз при инициализации, прежде чем его значение потребуется/прочитано. Функциональность pureComputed может выполнять то же самое с дополнительными преимуществами в течение срока службы вычисляемого (http://knockoutjs.com/documentation/computed-pure.html).

extend({deferred: true}) выберет observable/observableArray/computed в функции отложенных обновлений. Отложенные обновления означают, что вы можете синхронно выполнять несколько обновлений наблюдаемого/наблюдаемого массива или зависимостей вычисляемого, и это вызовет только одно изменение (которое происходит асинхронно). Это может быть очень полезно для сложного пользовательского интерфейса, так как вы избежите многократного повторного рендеринга для промежуточных изменений.

Если бы я запускал новое приложение, я бы включил отложенные обновления (ko.options.deferUpdates = true) и максимально использовал ko.pureComputed для лучшей производительности и использования памяти.

person RP Niemeyer    schedule 31.01.2017