ホームページ > 記事 > ウェブフロントエンド > Vue の応答性の原則は何ですか?
最近、Vue の原則に関する記事をたくさん読みました。これらの記事を参考に、自分自身で Vue のソース コードを理解しようと何度も試みました。いよいよ私自身がアウトプットしてみようと思いますが、他の記事とは違った視点で皆さんに Vue を知っていただければと思います。
var Dep = function Dep() { this.id = uid++ this.subs = [] }
Dep の意味は当然依存関係 (つまり依存、コンピュータ分野の名詞) です。
node.js プログラムを作成するのと同じように、npm ウェアハウスの依存関係がよく使用されます。 Vue では、依存関係は特にリアクティブに処理されるデータを指します。後で説明するように、リアクティブ処理の重要な機能の 1 つは、多くの Vue 原則に関する記事で言及されている defineReactive です。
Dep が各応答データにバインドされると、応答データは依存関係 (名詞) になります。以下で Watcher を紹介するときに、応答データが監視、計算、またはテンプレートで使用される可能性があることに言及します。依存(動詞)の 3 つのケース。
#subs
Dep オブジェクトの下に配列である subs 属性がありますが、これが購読者リストを意味していることは容易に推測できます。サブスクライバは、監視関数、計算関数、またはビュー更新関数の場合があります。
Watcher は、Dep で言及されているサブスクライバです (後の Observer オブザーバと混同しないでください)。
Watcher の機能は、一部のアプリの購読プッシュと同じように、Dep の更新にタイムリーに応答することであるため、あなた (Watcher) が特定の情報 (Dep) を購読すると、次の情報を読むよう通知されます。情報が更新されたとき。
deps
Dep が subs 属性を持つのと同様に、Watcher オブジェクトにも deps 属性があります。これは、Watcher と Dep の間に多対多の関係を構成します。相互に記録する理由は、一方のパーティがクリアされると、関連するオブジェクトを適時に更新できるためです。
Watcher の生成方法
上で何度も説明した監視テンプレート、計算テンプレート、レンダリング テンプレートによって Watcher が生成されます。これらはすべて Vue ソース コードで簡潔で理解しやすいものです。 :
Observer はオブザーバーであり、再帰的に実行する責任があります。リアクティブなオブジェクト (または配列) を観察 (または処理) します。印刷された例では、反応性オブジェクトに __ob__ が付いていることがわかります。これは、観察されたことの証拠です。オブザーバーは上記の Dep や Watcher ほど重要ではなく、少し理解するだけで十分です。
walk
Observer.prototype.walk は Observer の初期化時の再帰処理の中核となるメソッドですが、このメソッドはオブジェクトの処理に使用され、Observer もあります。 prototype.observeArray 配列を処理します。
上記の概念間の関係に従って、それらをどのように一致させ、応答性の高いデータ更新を実現するか?
最初に目標を設定します。当然、データが更新されると、ビューが自動的に更新されて最新のデータが表示されます。
これは上記の Dep と Watcher の関係で、データは Dep、Watcher はページ レンダリング関数をトリガーします (これが最も重要な Watcher)。
しかし、新たな疑問が生じます。ウォッチャーが自分を依存していることを、デップはどのようにして知るのでしょうか?
Vue は非常に興味深い方法を採用しています:
Watcher のコールバック関数を実行する前に、まず現在の Watcher が何であるかを (Dep.target を通じて) 書き留めます
実行中のコールバック関数でレスポンシブ データが使用されている場合、必然的にレスポンシブ データのゲッター関数が呼び出されます。 data 現在の Watcher を書き留めて、Dep と Watcher の間の関係を確立できます。
その後、レスポンシブ データが更新されると、必然的にレスポンシブ データの setter 関数が呼び出されます
以前に確立された関係に基づいて、ウォッチャーに対応するコールバック関数をセッター関数でトリガーできます
コード
defineReactive 関数は非常に重要で長くないため、ここに直接投稿する方が便利です。
function defineReactive(obj, key, val, customSetter, shallow) { var dep = new Dep() depsArray.push({ dep, obj, key }) var property = Object.getOwnPropertyDescriptor(obj, key) if (property && property.configurable === false) { return } // cater for pre-defined getter/setters var getter = property && property.get var setter = property && property.set var childOb = !shallow && observe(val) Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter() { var value = getter ? getter.call(obj) : val if (Dep.target) { dep.depend() if (childOb) { childOb.dep.depend() if (Array.isArray(value)) { dependArray(value) } } } return value }, set: function reactiveSetter(newVal) { var value = getter ? getter.call(obj) : val // 后半部分诡异的条件是用于判断新旧值都是 NaN 的情况 if (newVal === value || (newVal !== newVal && value !== value)) { return } // customSetter 用于提醒你设置的值可能存在问题 if ('development' !== 'production' && customSetter) { customSetter() } if (setter) { setter.call(obj, newVal) } else { val = newVal } childOb = !shallow && observe(newVal) dep.notify() }, }) }
まず第一に、各応答値は「依存関係」であるため、最初のステップでは、クロージャーの機能を使用して各値の Dep を作成します。 (Vue 3 では、クロージャは必要ありません)
次に、3 つのコア パラメータを見てみましょう:
obj 現在、値を応答的に処理する必要があるオブジェクト
key value key
val current value
この値は、独自の値より前に定義されている可能性があります。 getter と setter が存在するため、Vue の応答処理を実行するときは、元の getter と setter が最初に処理されます。
以下に、Dep と Watcher が相互に呼び出すためのいくつかのメソッドを示します。
Dep.prototype.depend = function depend() { if (Dep.target) { Dep.target.addDep(this) } } Watcher.prototype.addDep = function addDep(dep) { var id = dep.id if (!this.newDepIds.has(id)) { this.newDepIds.add(id) this.newDeps.push(dep) if (!this.depIds.has(id)) { dep.addSub(this) } } } Dep.prototype.addSub = function addSub(sub) { this.subs.push(sub) }
通过这几个函数,可以领略到了 Dep 和 Watcher 错综复杂的关系……不过看起来迂回,简单来说,其实做的就是上面说的互相添加到多对多列表。
你可以在 Dep 的 subs 找到所有订阅同一个 Dep 的 Watcher,也可以在 Watcher 的 deps 找到所有该 Watcher 订阅的所有 Dep。
但是里面还有一个隐藏问题,就是 Dep.target 怎么来呢?先放一放,后会作出解答。先接着看看 setter 函数,其中的关键是 dep.notify()。
Dep.prototype.notify = function notify() { // stabilize the subscriber list first var subs = this.subs.slice() for (var i = 0, l = subs.length; i < l; i++) { subs[i].update() } }
不难理解,就是 Dep 提醒他的订阅者列表(subs)里的所有人更新,所谓订阅者都是 Watcher,subs[i].update() 调用的也就是 Watcher.prototype.update。
那么来看一下 Watcher 的 update 做了什么——
Watcher.prototype.update = function update() { if (this.lazy) { this.dirty = true } else if (this.sync) { this.run() } else { queueWatcher(this) } }
在这里我觉得有两个点比较值得展开,所以挖点坑
以上がVue の応答性の原則は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。