This is the first day of my participation in the August Text Challenge.More challenges in August
A clock, under normal circumstances, we only know that the second hand should move once a second, so why does it move once a second, this requires us to understand the structure of the clock, so that it can be repaired when it goes wrong. Vue is the same, usually know how to use the development line, but suddenly appeared a inconsistent with the expected results, master some source knowledge can help you quickly locate the problem; On the other hand, interviews tend to be biased towards source code, and if you don’t, then you’re behind others. To do this, I also had to take the time to learn the source code to deal with the inner volume.
Source code analysis
- The listener
Observer
Intercepts all properties and listens for property changes
// core/instance/state.js
function initData(){...// Whether data is an object
// Attribute weight and other operations
observe(data, true /* asRootData */) // Listen for data
}
Copy the code
// core/observer/index.js
export function observe(value, asRootData){
let ob
ob = new Observer(value) // Create a listener instance
return ob
}
Copy the code
// core/observer/index.js
export class Observer{
constructor(value) {
if (Array.isArray(value)) { // Is an array type
/ / rewrite array methods' push ', 'pop', 'shift' and 'unshift', 'splice', 'sort of' reverse '
// ...
} else {
this.walk(value)
}
}
walk(obj) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i]) // Iterate over attributes to add interception}}}Copy the code
// core/observer/index.js
export function defineReactive(){
const dep = new Dep() // Each attribute corresponds to a Dep,
// ...! shallow && observe(val)// There may be nested objects in data, continue recursion
Object.defineProperty(obj, key,{
get(){
dep.depend() // Triggered when watcher access is collected in get
},
set(){ childOb = ! shallow && observe(newVal)// Set assigns an object and continues to recursively intercept the object
dep.notify() // Publish subscription messages}})}Copy the code
- A single piece of data can be used in more than one place on a page, so one attribute can correspond to more than one
Watcher
, set aDep
To manage theWatcher
// core/observer/dep.js
class Dep(a){
depend(){
if (Dep.target) { //Dep.target is a watcher
Dep.target.addDep(this)
}
}
addSub (sub: Watcher) {
this.subs.push(sub) // One Dep corresponds to multiple Watcher
}
notify () {
for (let i = 0, l = subs.length; i < l; i++) { // Walk through the collected Watcher,
subs[i].update()// Update Watcher in sequence}}}Copy the code
- The subscriber
Watcher
Receive property changes to update the corresponding view
// core/observer/watcher.js
class Watcher(a){
addDep(dep){
dep.addSub(this) // Add watcher to dep.subs, which holds the watcher list
}
update() {
// Synchronous or asynchronous update?
this.run()
}
run(){
const value = this.get() // Get the current value
if( value ! = =this.value ||
isObject(value) ||
this.deep
){ // The old value is not equal to the new value, the value is an object, deep mode
this.cb.call(this.vm, value, oldValue) // Execute Watcher's callback function}}get(){
value = this.getter.call(vm, vm) // Refire the property's get method to collect the watcher
this.cleanupDeps()
return value
}
cleanupDeps() {
// Run through all dePs and remove the subscription to Watcher from each Dep
let i = this.deps.length
while (i--) {
const dep = this.deps[i]
if (!this.newDepIds.has(dep.id)) {
// Remove the obsolete Watcher based on the subscribed ID to avoid the additional cost of updating
dep.removeSub(this)}}// assign newDeps,newDepIds to depIds, deps, and empty
let tmp = this.depIds
this.depIds = this.newDepIds
this.newDepIds = tmp
this.newDepIds.clear()
tmp = this.deps
this.deps = this.newDeps
this.newDeps = tmp
this.newDeps.length = 0}}Copy the code
The specific process
Depend on the collection
The get () = = = > dep. Depend () = = = > (dep. The target is the Watcher) dep. Target. AddDep () = = = > dep. AddSub ()
- Property is triggered when the property is read
get
Interceptor operations - Into the
Dep
Object, one for each propertyDep
, the use ofdep.depend()
Method to collect related dependencies - Into the
watcher.addDep
Method,Watcher
Object has onenewDeps
andnewDepIds
Property, which is stored with thisWatcher
The relevantDep
Object, oneWatcher
Corresponding to multipleDep
.newDeps
What’s stored inside isDep
The list of - Back to the
Dep
Object, place thisWatcher
Added to thesubs
Property, oneDep
Corresponding to multipleWatcher
graph LR;
prop1-->dep1-->watcher1
prop2-->dep2-->watcher2 & watcher1
prop3-->dep3-->watcher3 & watcher2
prop4-->dep4-->watcher4
Distributed update
set()--->dep.notify()--->watcher.update()--->watcher.run()--->watchrt.get()--->this.getter.call(vm, vm)--->watcher.cleanupDeps()---> this.cb.call(this.vm, value, oldValue)
- Triggered when assigning a value to a property
set()
Interceptor operations - Go to the corresponding of this property
Dep
Object, traversalsubs
Property to store inwatcher
List, ready for update - When an update is made, it determines whether the update is synchronous or asynchronous, and then performs different operations in a more updated manner
- Sync updates into
run()
Method, triggerget()
Method to get the updated value - Enter the
get()
The method is called againhis.getter.call(vm, vm)
The triggergetter
Interceptor, gets the value of the property, and recollects the dependency - Triggered after the dependency is recollected
clearupDeps()
Clean up ‘Watcher’ that is not relevant to the current update - perform
watcher
The callback function in
The articles
- [Vue source]–$nextTick and asynchronous rendering (line by line comments)
- [Vue source]–mixin and extend (line by line)
- [Vue source]–Diff algorithm (line by line comment)
- [Vue source]– How to listen for array changes (line by line comment)
- [Vue source]– Reactive (bidirectional binding) principle (line by line comment)
- [Vue source]– what is done for each lifecycle (line by line comments)
- [Vue source]– How to generate virtual DOM (line by line comment)