ViewModel系フレームワークでデータの変化を監視させない
実は最近 Vue.js ばかりいじっていて、その時に
data の変更を component が全部検知してしまうとモノによってはパフォーマンスペナルティがでかいのでは?
と気になったので、ついでにメジャーなフレームワークについて「監視させない方法」を調べてみた。今回調べたのは以下の4つ。
- Vue.js
- Mithril
- React
- Angular (2+)
ちなみに React 以外をちらっと触ったことある程度なので、間違えてる可能性はおおいにあります!!1
Vue.js
Vue の場合は data あるいは data() で「ビルド時に明示されていないもの」は自動監視できない。
つまり created() などで this に対して値をセットするとそれは auto redraw の対象から外れるので変化の激しいオブジェクトなどはこのような方法で与えるとよい。
data() {
return {}
},
created() {
this.nowatch = NotWatchedObject
}
Mithril
Mithril にはデータの変更を自動検知して redraw する機能は存在しない。あくまで VM component はイベントハンドラ実行後に redraw を行う。つまり特定の値の変更に寄与する関数を Mithril に明示しない限り component は値の変更、変化の影響を受けない。
したがって自由に外の世界を統べる World オブジェクトなどを配置することができる。
はず。
React
class ベースの React.component は state と props が監視対象であり、それ以外の property は自由に使える。
While this.props is set up by React itself and this.state has a special meaning, you are free to add additional fields to the class manually if you need to store something that doesn’t participate in the data flow (like a timer ID).
Angular 2+
Angular 2+ は Zone というライブラリを使って
- ユーザーの fire したイベント
- XHR
- タイマー
を監視しており、この結果の component の変化は自動で検知(Change Detection)される。
- 日本語訳:Angular 2 Change Detection Explained - Qiita
- Angularでイベントから無駄にChange Detectionを走らせないためにすべきこと - Qiita
NgZone#runOutsideAngular の中で実行したものは Change Detection の対象外になるらしいので、特定の property の変更に寄与するイベントをこれで囲んであげるとよさげ。
まとめ
これまであまり気にしていなかったが、実はメジャーなViewModel系のフレームワークの考え方は
- 特定のデータ監視系(React, Vue)
- イベント監視系(Mithril)
- 非同期処理監視系(AngularJS)
に分類できることが分かった。(あえて言うと 2 は 3 の簡略版みたいなものと言えるかもしれない。)