LoginSignup
7
7

More than 5 years have passed since last update.

[JS]KnockoutJS 3.0 Upgrade Noteを読む 第1弾

Last updated at Posted at 2013-10-27

はじめに

KnockoutJSの3.0がリリースされましたね。
Upgrade Notesを読んで分かった事をまとめます。
今回は、「1. Computed properties now notify only when their value changes」を読みます。

説明を読むと、2.xまではcomputedが評価された際は、必ず変更したとういう通知が行くそうです。subscribeでコールバックを仕掛ければ、その通知を受取ることができます。3.0では、computedが評価された結果が前回と同じであれば、通知がいかないようになっています。

文章だけ見ると、分かったようで分からないので、KnockoutJSのソースコードを読みましょう。

2.3.0のコード

2.3.0のコードを見てみます。
https://github.com/knockout/knockout/blob/v2.3.0/src/subscribables/dependentObservable.js#L80-L84

evaluateImmediateが呼ばれると、値の更新とその事の通知が行なわれているのが分かります。ただし、依存しているobservableが更新されないとevaluateImmediateが呼ばれずに、前回評価した値を使うので注意が必要です。

2.3.0.dependentObservable.js
function evaluateImmediate() {
    //...
    // ここで値の更新と通知している
    dependentObservable["notifySubscribers"](_latestValue, "beforeChange");
    _latestValue = newValue;
    dependentObservable["notifySubscribers"](_latestValue);
    //...
}

3.0.0のコード

次に、3.0.0のコードを見てみます。
https://github.com/knockout/knockout/blob/v3.0.0/src/subscribables/dependentObservable.js#L85-L91

2.3.0に無かったif文が追加されているのが分かります。
見ての通り、値に変化がなかったら更新も通知もしないというものです。

3.0.0.dependentObservable.js
function evaluateImmediate() {
    //...
    // 変更なければ、更新も通知もしない
    if (!dependentObservable['equalityComparer'] || !dependentObservable['equalityComparer'](_latestValue, newValue)) {
        dependentObservable["notifySubscribers"](_latestValue, "beforeChange");
        _latestValue = newValue;
        dependentObservable["notifySubscribers"](_latestValue);
    }
    //...
}

動かして違いを見る

ソースコード上の違いが分かったので、実際に動きの違いを見てみましょう。
以下のコードには、nというobservableevenNというcomputedがでてきます。nには数値が入り、evenNnが偶数だったらtrueを返すようにしてあります。
2.xの場合、evenNの結果が同じでも通知がいきます。例えば、以下のコードでは、はじめn10が入っており、その後20に変わっています。どちらも偶数なので、evenNは共にtrueになります。evenNの値は変わっていないので、通知はいってほしくないですが、2.xの場合は通知がいってしまいます。
一方、3.0.0の場合は、n(20)ではevenNの値は変わらないので、通知はいいません。n(21)では、奇数になるので、evenNの値はfalseとなるので、通知がいきます。

JSFiddleで動作を確認してみましょう。
2.3.0:http://jsfiddle.net/uedatakuya/TdErN/
3.0.0:http://jsfiddle.net/uedatakuya/xxK9E/

var n = ko.observable(10);

var evenN = ko.computed(function() {
    var isEven = n() % 2 == 0;
    alert(isEven);
    console.log(isEven);
    return isEven;
});

evenN.subscribe(function(newValue) {
    alert("change evenN to " + newValue);
    console.log("change evenN to " + newValue);
});

n(20);
n(21);

挙動が変わると困る場合

上述のように、3.0.0では2.xと挙動が変わります。2.xの挙動と同じようにしたい場合は、Upgrade Notesに書いてある通り、myComputed.extend({ notify: 'always' });のように、必ず通知がいくようにしましょう。

var n = ko.observable(10);

var evenN = ko.computed(function() {
    var isEven = n() % 2 == 0;
    alert(isEven);
    console.log(isEven);
    return isEven;
});

// 必ず通知がいくようにする
evenN.extend({notify: 'always'});

evenN.subscribe(function(newValue) {
    alert("change evenN to " + newValue);
    console.log("change evenN to " + newValue);
});

n(20);
n(21);
7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7