阻止するための前列
主な記事
レスポンシブの原則を明確にするためには、まず、VueのソースコードにおけるObserver Watcher Dep3クラスの役割とその関係を把握する必要があります。
この3つのクラスの関係やつながりが明確になれば、レスポンシブの一般原則が理解できます。
オブザーバーは、その主な役割は、深く値を取るたびに、値がいくつかのカスタムメソッドを実行するように、耳を傾けることができる設定するように、ハイジャック、データをリッスンすることです。
Wathcer, watch は Observer によって処理されるデータで、ビューのレンダリングと更新を担当します。
Dep はレンダリングウォッチャーを記録し、レンダリングウォッチャーにビューの更新を通知します。ログが記録されないと、Dep はデータが変更されたときに誰に通知すればいいのかわかりません。
データオブザーバ
まずはレスポンシブエントリーのオブザーバーから。
もし渡すデータがオブジェクトであれば、Observerはこのオブジェクトの各キー値に対してReactiveを定義します。Object.defineProperty
では、ゲッターとセッターでは何が行われるのでしょうか?
Getter
Observerは各属性に、属性の依存関係を管理するための新しいDepインスタンスを与え、このデータ(Object)の値を取ると、Depインスタンスは現在のレンダリングWatcherを記憶します。
Setter
このデータ(Object)の値を設定し、テンプレートを更新する必要がある場合、depepはそれをremember watcherに通知します!
この時点で、オブザーバー、デップ、ウォッチャーの関係は判明しているでしょう。
盗まれたものです。
簡単に言うと、データのハイジャックを行うのはObserverで、Watcherはビューを更新し、DepはObserverとWatcherの橋渡しをし、Watcherがデータの変更を更新するのを記録します。
以上のまとめを念頭に置いて、オブザーバーについて話を続けましょう。
Object.defineProperty
dataがObjectの場合、defineReactiveを定義し、それを使ってハイジャックする、と書いてあります。
では、データが配列の場合はどうでしょうか?
実際、レスポンシブでは、配列の処理は、Arrayのプロトタイプメソッドをオーバーライドするという別のメカニズムを呼び出します。
一言で言えば、pushなどの配列メソッドを呼び出す際に、ネイティブ配列のpushメソッドを実行する前に、独自に定義したpushを呼び出すということです。
実現の詳細は
1、まず配列のプロトタイプをコピーします。
let arrayMethods = Object.create(Array.prototype)
2, 次に、作成したプロトタイプオブジェクトで、配列自体を変更する7つのメソッドを書き換えます。
// これら7つのメソッドは、元の配列を変更することができる
let methods = [
'push',
'pop',
'shift',
'unshift',
'sort',
'reverse',
'splice'
]
methods.forEach(method=>{
arrayMethods[method] = function (...args) {
// そして、メソッド内のメソッドを呼び出すと、データを観察する。
// 次に、ネイティブ配列メソッドを再度呼び出す
Array.prototype[method].apply(this,args);
}
})
3.最終変更データのプロトタイプチェーン
data.__proto__ = arrayMethods;
そして、data.pushを実行すると、まずpushの内部でarrayMethodsが実行され、最後にarrayMethodsの中で独自のロジックを処理した後、Array.pushを呼び出すことで、ネイティブのArrayを書き換える効果が得られます。
あなたが観察するために、配列の各項目をループする必要がないように、このメカニズムのためだけでなく、配列の添え字への直接呼び出しにつながるビューを更新することはできません、あなたは、セットメソッドを呼び出す必要があります。
データ派遣センターに依存
Observerの話になると、データをフェッチするときにdependency collectionのためにdep.dependが呼ばれ、実際には対応するWatcherをsubs配列にプッシュしているとのことでした。
この配列が配置された状態で、プロパティに設定する場合は、dep.notifyを呼び出します。dep.notifyは、実際にサブの各ウォッチャーを取り込んで更新を実行します。
notify(){
this.subs.forEach(watcher=>watcher.update())
}
デップとウォッチャーは多対多の関係にあります。
各プロパティには、ウォッチャーを保持するdep属性があります。
---1つのウォッチャーが複数の属性に依存することがあるため、-depには複数のウォッチャーが存在する可能性があります。
サブスクライバウォッチャー
dep 内部の subs 配列は、ビューのレンダリングと更新を行うレンダリングウォッチャーを保持します。
dep.notifyが呼び出されると、このプロパティのすべてのウォッチャーに対してupdateメソッドが呼び出されます。
updateメソッドの役割は、ビューを更新しに行くことですが、ここではパフォーマンスを節約するために、アンチシェイクに似たnextTick最適化を使用します。
おそらくプロセス全体がそうでしょう:
update を呼び出した後、nextTick で最適化します。update コールバック関数を再度呼び出します。
この更新コールバック関数は、新しいrender関数を生成し、renderは新しいVnodeを生成し、Vnodeはビューをレンダリングする実際のdomを生成します。
これで、データ変更からテンプレート更新までのプロセスは完了です。