English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Vue.jsの原理分析におけるobserverモジュール詳細

紹介

observerはVueの核心で最も重要なモジュール(個人的には)であり、ビューとデータの応答性の更新を実現し、下層は完全にobserverのサポートに依存しています。

注意:この記事はVue@に対応しています2.1.8分析を行います

observerモジュールはVueプロジェクトのsrc内の位置にあります/core/observer、モジュールは以下の部分に分かれています:

  1. Observer: データの観察者であり、データオブジェクトの読み書き操作が観察者の監視下に置かれます
  2. Watcher: データの購読者であり、データの変更がWatcherに通知され、Watcherが対応する操作を行います、例えばビューの更新など
  3. Dep: ObserverとWatcherの結びつき、データが変更された場合、Observerによって観察され、DepによってWatcherに通知されます

以下の図に示されています:

Observer

Observerクラスはsrcに定義されています/core/observer/index.jsでは、まずObserverのコンストラクタを見てみましょう

constructor (value: any) {
 this.value = value
 this.dep = new Dep()
 this.vmCount = 0
 def(value, '__ob__', this)
 if (Array.isArray(value)) {
 const augment = hasProto
 ? protoAugment
 : copyAugment
 augment(value, arrayMethods, arrayKeys)
 this.observeArray(value)
 }
 this.walk(value)
 }
}

valueは観察される必要があるデータオブジェクトであり、コンストラクタではvalueに__ob__属性を追加し、データがObserverによって観察されているシグナルとして使用します。valueが配列の場合は、observeArrayを使用してvalueを巡回し、valueの中の各要素にobserveを呼び出してそれぞれ観察します。valueがオブジェクトの場合は、walkを使用してvalue上の各keyを巡回し、各keyに対してdefineReactiveを呼び出してそのkeyのsetを取得します。/getを制御権を得ます。

上で使用したいくつかの関数の機能について説明します:

  • observeArray: 配列を巡回し、配列の各要素にobserveを呼び出します
  • observe: オブジェクトに__ob__属性があるかどうかをチェックし、あればそのオブジェクトはすでにObserverの監視下にあります。なければ、new Observerを使用してオブジェクトを監視します(実際にはいくつかの判断ロジックもありますが、理解を容易にするために省略します)
  • walk: オブジェクトの各keyを巡回し、オブジェクトの各keyのデータにdefineReactiveを呼び出します
  • defineReactive: Object.definePropertyを使用してオブジェクトのkey属性を設定し、その属性値のsetをキャッチするために使用します/getアクション。一般的にはWatcherのインスタンスがget操作を実行し、その場合Watcherのインスタンスは自動的にDepインスタンスの依存関係の配列に追加されます。外部操作がsetをトリガーした場合、Depインスタンスのnotifyを通じてすべての依存関係のWatcherに更新を通知します。

上記のテキスト説明が理解できない場合は、以下の図を参照してください:

Dep

DepはObserverとWatcherの橋渡しであり、DepはObserverに従事するサブスクライブシステムとも考えられます。Watcherは特定のObserverのDepをサブスクライブし、Observerが監視するデータが変更された場合、Depを通じてサブスクライブしたすべてのWatcherに通知されます。

Depはいくつかのインターフェースを提供します:

  • addSub: パラメータとしてWatcherインスタンスを受け取り、Watcherインスタンスを依存関係の配列に保存する
  • removeSub: addSubに対して、Watcherインスタンスを依存関係の配列から削除する
  • depend: Dep.targetに現在操作する必要があるWatcherインスタンスが保存されています。dependを呼び出すと、WatcherインスタンスのaddDepメソッドが呼び出されます。addDepの機能は以下のWatcherの紹介を参照してください
  • notify: 依存関係の配列に含まれるすべてのWatcherを更新操作に通知する

Watcher

Watcherはデータの変化を購読して、それに応じた操作(例えばビューの更新)を実行するために使用されます。Watcherのコンストラクタ関数は以下のように定義されています:

constructor (vm, expOrFn, cb, options) {
 this.vm = vm
 vm._watchers.push(this)
 // options
 if (options) {
 this.deep = !!options.deep
 this.user = !!options.user
 this.lazy = !!options.lazy
 this.sync = !!options.sync
 }
 this.deep = this.user = this.lazy = this.sync = false
 }
 this.cb = cb
 this.id = ++uid // uid for batching
 this.active = true
 this.dirty = this.lazy // for lazy watchers
 this.deps = []
 this.newDeps = []
 this.depIds = new Set()
 this.newDepIds = new Set()
 this.expression = process.env.NODE_ENV !== 'production'
 ? expOrFn.toString()
 : ''
 if (typeof expOrFn === 'function') {
 this.getter = expOrFn
 }
 this.getter = parsePath(expOrFn)
 if (!this.getter) {
 this.getter = function () {}
 process.env.NODE_ENV !== 'production' && warn(
 `watching path: "${expOrFn}" に失敗しました` +
 'Watcherはシンプルなドットのみを受け入れます。'-区切られたパス。' +
 '完全な制御には、関数を使用してください。'
 vm
 )
 }
 }
 this.value = this.lazy
 ? undefined
 : this.get()
}

パラメータでは、vmはコンポーネントインスタンスを示し、expOrFnはサブスクリプトするデータフィールド(例:a.b.c)または実行する関数を示します。cbはwatcherの実行後のコールバック関数、optionsはオプションオブジェクトで、deep、user、lazyなどの設定を含みます。

watcherインスタンスには以下のメソッドがあります:

  • Dep.targetを現在のwatcherインスタンスに設定し、内部でthis.getterを呼び出します。この時、Observerで監視されているデータオブジェクトが参照された場合、現在のwatcherインスタンスが自動的にデータオブジェクトのDepインスタンスにサブスクリプトされます。
  • addDep: 引数dep(Depインスタンス)を受け取り、現在のwatcherがdepにサブスクリプションするようにします
  • cleanupDeps: newDepIdsとnewDepに記録されたdepのサブスクリプション情報をクリーンアップ
  • update: 即座にwatcherを実行するか、watcherをキューに追加して統一flushを待つ
  • run: watcherを実行し、this.get()を呼び出して評価し、その後コールバックをトリガー
  • evaluate: this.get()を呼び出して評価
  • depend: this.depsを巡回し、現在のwatcherインスタンスがすべてのdepにサブスクリプションするようにします
  • teardown: 現在のwatcherインスタンスのすべてのサブスクリプションを削除

配列メソッド

src/core/observer/array.jsで、Vueフレームワークはpush、pop、shift、unshift、sort、splice、reverseメソッドを改造しており、これらのメソッドを呼び出すと自動的にdep.notify()が呼び出され、これらの関数を呼び出して配列を変更した後に更新がトリガーされない問題を解決します。

Vueの公式ドキュメントではこの点についても説明されています:http://cn.vuejs.org/v2/guide/list.html#変異メソッド

まとめ

これでこの記事のすべての内容が終わりました。この記事の内容が皆様の学習や仕事に少しでも役立つことを願っています。何か疑問があれば、コメントを残してください。

声明:この記事の内容はインターネットから収集され、著作権者に帰属します。インターネットユーザーによって自発的に提供され、アップロードされました。このサイトは所有権を持ちません。人工編集は行われていません。また、関連する法的責任も負いません。著作権侵害を疑われる内容がある場合は、メールを送信してください:notice#oldtoolbag.com(メール送信時、#を@に置き換えてください。申し訳ありませんが、報告を行い、関連する証拠を提供してください。一旦確認が取れましたら、このサイトは即座に侵害を疑われるコンテンツを削除します。)

おすすめ