[JS]KnockoutJS 3.0 Upgrade Noteを読む 第1弾
October 27, 2013
この記事はQiitaの記事をエクスポートしたものです。内容が古くなっている可能性があります。
はじめに
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
が呼ばれずに、前回評価した値を使うので注意が必要です。
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文が追加されているのが分かります。 見ての通り、値に変化がなかったら更新も通知もしないというものです。
function evaluateImmediate() {
//...
// 変更なければ、更新も通知もしない
if (!dependentObservable['equalityComparer'] || !dependentObservable['equalityComparer'](_latestValue, newValue)) {
dependentObservable["notifySubscribers"](_latestValue, "beforeChange");
_latestValue = newValue;
dependentObservable["notifySubscribers"](_latestValue);
}
//...
}
動かして違いを見る
ソースコード上の違いが分かったので、実際に動きの違いを見てみましょう。
以下のコードには、n
というobservable
とevenN
というcomputed
がでてきます。n
には数値が入り、evenN
はn
が偶数だったらtrue
を返すようにしてあります。
2.xの場合、evenN
の結果が同じでも通知がいきます。例えば、以下のコードでは、はじめn
に10
が入っており、その後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' });
のように、必ず通知がいくようにしましょう。
http://jsfiddle.net/uedatakuya/sKHgg/
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);