Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is difference on ko.computed between deferEvaluation and extend({deferred: true})

I am little bit confused by behavior explanation of deferred calculation defined on ko.computed variable.

Such computed variable might be defined with property deferEvaluation: true which should postpone evaluation to the moment when any other property ask for variable value (see http://knockoutjs.com/documentation/computed-reference.html),

When regular ko.computed variable is extended by extend({deferred: true}) it calls calculation asynchronously and postpone it until all currently running "threads" finishes (see http://knockoutjs.com/documentation/deferred-updates.html).

These two settings sound very similar, but each do something completely different.

Can anybody confirm to me that I am right or explain the difference if I am mistaken?

like image 587
Jan Stanicek Avatar asked Jan 31 '17 14:01

Jan Stanicek


1 Answers

deferEvaluation is only about deferring initial evaluation. Normally when you create a computed, its evaluator is called right then, synchronously, which means (amongst other things) that all of the observables it depends on must already be initialized. Using deferEvaluation prevents that, and makes the first call to the computed's evalutor function happen the first time anything subscribes to the computed (or never, if nothing ever does). After that, it has no further effect; the computed is still re-evaluated every time anything it depends on changes, immediately.

.extend({deferred: true}) is about always deferring execution of the evaluator until after the task that created or changed it completes (and then typically before the next UI update). It's not just about the initial evaluation, it means every time the observables the computed depends on change, those changes are allowed to settle by making the computed's evaluation asynchronous (after the current task) and waiting for them to stabilize.

Here's a snippet showing using neither of them, using deferEvaluation and using .extend({deferred: true}). Note the differences in when the evaluators are called.

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>
like image 155
T.J. Crowder Avatar answered Oct 19 '22 12:10

T.J. Crowder