Heim >Web-Frontend >js-Tutorial >Prinzip der Abhängigkeitssammlung des Vue-Quellcodes
Dieser Artikel stellt hauptsächlich das Abhängigkeitssammlungsprinzip des Vue-Quellcodes vor. Er hat einen gewissen Referenzwert. Jetzt kann ich ihn mit allen teilen, die ihn benötigen.
Vue ist derzeit die dritte inländische Front. End-Web-End. Es ist auch einer meiner wichtigsten Technologie-Stacks. Ich kenne es im täglichen Gebrauch und bin gespannt, warum es eine große Anzahl von Artikeln zum Lesen von Vue-Quellcode gibt In letzter Zeit möchte ich diese Gelegenheit nutzen, um von allen zu lernen. Ich habe aus den Artikeln und Diskussionen etwas gewonnen, habe beim Lesen des Quellcodes einige Gedanken zusammengefasst und einige Artikel als Zusammenfassung meiner eigenen Gedanken erstellt . Mein Level ist begrenzt, also hinterlassen Sie bitte eine Nachricht zur Diskussion~
Target Vue-Version: 2.5.17-beta.0
Vue-Quellcode-Kommentare: https://github.com/SHERlocked...
Haftungsausschluss: Die Syntax des Quellcodes im Artikel verwendet Flow und der Quellcode wird nach Bedarf gelöscht (um nicht verwirrt zu werden@_@). Wenn Sie die Vollversion sehen möchten, geben Sie bitte oben die Github-Adresse ein. Bei diesem Artikel handelt es sich um eine Artikelserie unten kümmert sich nicht um Ansichtsänderungen, sondern steuert Ansichtsaktualisierungen über Daten, was unsere Zustandsverwaltung sehr einfach macht. Ein Bild von der offiziellen Website stehlen
Instanzobjekt, das die Eigenschaften während des Komponentenrenderingprozesses und dann als Abhängigkeiten aufzeichnet Wenn das einer Abhängigkeit aufgerufen wird, benachrichtigt es das
zur Neuberechnung, wodurch die zugehörigen Komponenten aktualisiert werden.Watcher
Hier gibt es drei wichtige Konzepte setter
, watcher
,
, Observe
, Dep
Watcher
src/core/observer/index.js
src/core/observer/dep.js
src/core/observer/watcher.js
befinden
Observe
getter/setter
Dep
Watcher
2. Code-Implementierung
// src/core/instance/state.js export function initState(vm: Component) { const opts = vm.$options if (opts.props) initProps(vm, opts.props) // 初始化props if (opts.methods) initMethods(vm, opts.methods) // 初始化methods if (opts.data) initData(vm) // 初始化data if (opts.computed) initComputed(vm, opts.computed) // 初始化computed if (opts.watch) initWatch(vm, opts.watch) // 初始化watch } }
, initState
,
, props
zu initialisieren, werfen wir einen Blick auf die Methode methods
, um einen Blick auf data
// src/core/instance/state.js function initData(vm: Component) { let data = vm.$options.data data = vm._data = typeof data === 'function' ? getData(data, vm) : data || {} observe(data, true /* asRootData */) // 给data做响应式处理 }
computed
zu werfen Bestimmt zunächst, ob es sich bei den Daten um eine Funktion handelt. Wenn nicht, wird eine wathcer
-Methode verwendet. Diese Methode versucht, eine Observer-Instanz zu erstellen Wenn es erfolgreich erstellt wurde, wird eine neue Observer-Instanz zurückgegeben. Die Instanz gibt die vorhandene Observer-Instanz zurück. initData
2.2 Observer/defineReactive
// src/core/observer/index.js export function observe (value: any, asRootData: ?boolean): Observer | void { let ob: Observer | void ob = new Observer(value) return ob }
observe
Diese Methode verwendet hauptsächlich data
as Ein Parameter zum Instanziieren einer Observer-Objektinstanz. Observer ist eine Klasse für die Sammlung und Aktualisierung von Abhängigkeiten. Der Konstruktor von Observer verwendet die Methode __ob__
, um auf die Schlüssel des Objekts zu reagieren, und fügt rekursiv zu den Attributen des Objekts hinzu aufgerufen, wenn die data
-Methode der Watcher-Instanz aufgerufen wird des Beobachters in notify
und schieben Sie den ursprünglichen Beobachter auf den Stapel defineReactive
. Nachdem der Beobachter des Werts übernommen wurde, nehmen Sie ihn vom Stapel und weisen Sie den ursprünglichen Beobachterwert getter/setter
zu, getter
und löschen Sie schließlich den Beobachter, die im neuen getter
nicht mehr vorhanden sind, um zu verhindern, dass nutzlose Beobachter, die in der Ansicht nicht mehr benötigt werden, ausgelöst werdensetter
zuerst getter
und zurückkehren, wenn sich im Vergleich zum alten keine Änderung ergibt Wenn eine Änderung auftritt, benachrichtigt dep alle Watcher-Instanzen Dep.target
, die zur Aktualisierung auf diese Daten angewiesen sind. Hier wird Dep.target
bei nextTick nimmt den Watcher in der Warteschlange heraus und führt get
aus und führt die entsprechende Hook-Funktion aus pushTarget
Dep.target
2.3 DeptargetStack
Dep.target
Ein Schlüsselwort cleanupDeps
wird oben oft erwähnt Es ist ein Container für Abhängigkeitssammlung, oder sie heißt newDeps
Abhängigkeitssammler
@liuhongyi0101 :简单点说就是引用计数 ,谁借了我的钱,我就把那个人记下来,以后我的钱少了 我就通知他们说我没钱了
而把借钱的人记下来的小本本就是这里 Dep
实例里的subs
// src/core/observer/dep.js let uid = 0 // Dep实例的id,为了方便去重 export default class Dep { static target: ?Watcher // 当前是谁在进行依赖的收集 id: number subs: Array<watcher> // 观察者集合 constructor() { this.id = uid++ // Dep实例的id,为了方便去重 this.subs = [] // 存储收集器中需要通知的Watcher } addSub(sub: Watcher) { ... } /* 添加一个观察者对象 */ removeSub(sub: Watcher) { ... } /* 移除一个观察者对象 */ depend() { ... } /* 依赖收集,当存在Dep.target的时候把自己添加观察者的依赖中 */ notify() { ... } /* 通知所有订阅者 */ } const targetStack = [] // watcher栈 export function pushTarget(_target: ?Watcher) { ... } /* 将watcher观察者实例设置给Dep.target,用以依赖收集。同时将该实例存入target栈中 */ export function popTarget() { ... } /* 将观察者实例从target栈中取出并设置给Dep.target */</watcher>
这里 Dep
的实例中的 subs
搜集的依赖就是 watcher 了,它是 Watcher
的实例,将来用来通知更新
// src/core/observer/watcher.js /* 一个解析表达式,进行依赖收集的观察者,同时在表达式数据变更时触发回调函数。它被用于$watch api以及指令 */ export default class Watcher { constructor( vm: Component, expOrFn: string | Function, cb: Function, options?: ?Object, isRenderWatcher?: boolean // 是否是渲染watcher的标志位 ) { this.getter = expOrFn // 在get方法中执行 if (this.computed) { // 是否是 计算属性 this.value = undefined this.dep = new Dep() // 计算属性创建过程中并未求值 } else { // 不是计算属性会立刻求值 this.value = this.get() } } /* 获得getter的值并且重新进行依赖收集 */ get() { pushTarget(this) // 设置Dep.target = this let value value = this.getter.call(vm, vm) popTarget() // 将观察者实例从target栈中取出并设置给Dep.target this.cleanupDeps() return value } addDep(dep: Dep) { ... } /* 添加一个依赖关系到Deps集合中 */ cleanupDeps() { ... } /* 清理newDeps里没有的无用watcher依赖 */ update() { ... } /* 调度者接口,当依赖发生改变的时候进行回调 */ run() { ... } /* 调度者工作接口,将被调度者回调 */ getAndInvoke(cb: Function) { ... } evaluate() { ... } /* 收集该watcher的所有deps依赖 */ depend() { ... } /* 收集该watcher的所有deps依赖,只有计算属性使用 */ teardown() { ... } /* 将自身从所有依赖收集订阅列表删除 */ }
get
方法中执行的 getter
就是在一开始new渲染watcher时传入的 updateComponent = () => { vm._update(vm._render(), hydrating) }
,这个方法首先 vm._render()
生成渲染VNode树,在这个过程中完成对当前Vue实例 vm
上的数据访问,触发相应一众响应式对象的 getter
,然后 vm._update()
去 patch
注意这里的 get
方法最后执行了 getAndInvoke
,这个方法首先遍历watcher中存的 deps
,移除 newDep
中已经没有的订阅,然后 depIds = newDepIds; deps = newDeps
,把 newDepIds
和 newDeps
清空。每次添加完新的订阅后移除旧的已经不需要的订阅,这样在某些情况,比如 v-if
已不需要的模板依赖的数据发生变化时就不会通知watcher去 update
了
整个收集的流程大约是这样的,可以对照着上面的流程看一下
watcher 有下面几种使用场景:
render watcher
渲染 watcher,渲染视图用的 watcher
computed watcher
计算属性 watcher,因为计算属性即依赖别人也被人依赖,因此也会持有一个 Dep
实例
watch watcher
侦听器 watcher
只要会被别的观察者 (watchers
) 依赖,比如data、data的属性、计算属性、props,就会在闭包里生成一个 Dep 的实例 dep
并在被调用 getter
的时候 dep.depend
收集它被谁依赖了,并把被依赖的watcher存放到自己的subs中 this.subs.push(sub)
,以便在自身改变的时候通知 notify
存放在 dep.subs
数组中依赖自己的 watchers
自己改变了,请及时 update
~
只要依赖别的响应式化对象的对象,都会生成一个观察者 watcher
,用来统计这个 watcher
依赖了哪些响应式对象,在这个 watcher
求值前把当前 watcher
设置到全局 Dep.target
,并在自己依赖的响应式对象发生改变的时候及时 update
以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!
相关推荐:
Das obige ist der detaillierte Inhalt vonPrinzip der Abhängigkeitssammlung des Vue-Quellcodes. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!