Previously on & Background
The createElm method, which creates real elements from VNode, contains two scenarios:
- if
VNode
Is a custom componentcreateComponent
Method processing; - If it is a normal element, it passes
nodeOps.createElement
Create a nativeHTML
Elements;
At the end of the last article, I combed the whole process of stack execution from new Vue to INSERT. This process is the whole process of Vue from new Vue to rendering to the page.
However, Vue is a responsive system, and the first half of the process is only completed, and the remaining half is when the responsive data changes, Vue’s rendering Watcher is notified to trigger the re-rendering, which is often referred to as the patch phase.
For the internal design of Vue itself, as long as the process of VNode rendering to the page is called patch, it is not divided into two big processes, although the internal differentiation is still the first rendering, you still respond to the change of data and render. But this is not friendly to beginners of Vue source code, so I smartly split it into two processes and gave them names;
- The first render we call him
First apply colours to a drawing
That’s the front oneMount the stage
For the first timeThe template
becomeDOM
Render to page; - This part right here is called
Patch phase
The next stage is reactive data updates that trigger re-rendering, your favoritedom diff
This is the cutie stage (she beats you a thousand times and you treat her like your first love);
Ii. Process analysis + sample code
To accommodate responsive data updating during patch, we added a button button# BTN to the template. The handler of the button click event will modify the data.forprop.a property:
forPatchComputed
This computes the property dependencydata.forProp
;<some-com />
component-receivedsomeKey
So is data bound to propdata.forProp
The test.html code is as follows:
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue</title>
</head>
<body>
<div id="app">
<button id="btn" @click="goForPatch">Make forProp. +</button>
<some-com :some-key="forProp"><div slot="namedSlot">SLOT-CONTENT</div></some-com>
<div>forPatchComputed = {{forPatchComputed}}</div>
<div class="static-div">Static node</div>
</div>
<script src="./dist1/vue.js"></script>
<script>
const sub = {
template: `
slot-fallback-content
{{ someKey.a + ' foo' }}
`.props: {
someKey: {
type: Object.default () {
return { a: '996-rejected!! '}}}};debugger
new Vue({
el: '#app'.data: {
forProp: {
a: 100}},methods: {
goForPatch () {
this.forProp.a++
}
},
computed: {
// Calculate attributes
forPatchComputed () {
return this.forProp.a + ' reject 996'}},components: {
someCom: sub
}
})
</script>
</body>
</html>
Copy the code
So when data.forProp is modified, there are now three Watcher triggers to update:
forPatchComputed
Evaluate the corresponding of the propertywatcher
, note the calculation of attributeswatcher
是lazy
;some-com
The correspondingRender the watcher
;div#app
Of the template for this root instanceRender the watcher
;
Trigger reactive updates
In the responsive system is an obvious observer mode, which requires us to make clear who is the observer, who is the observed, who is responsible for the communication between the two;
- The observer is
Watcher
Instance,watcher
From the literal it can be seen that the observer (watch
English translation is notWatch, watch
~); - The observed is the data itself, for example
data.forProp
This object; - The communication between the two is
Dep
Instance,Dep
Dependence is a noun, not a verbBe watcher rely on
If it becomes a verbRely on others
A); Every reactive data has itdep
.dep
In charge of collecting and using this datawatcher
, and then the data changes to send a notification, letwatcher
Take action;
3.1 Review the implementation of responsiveness
The responsivity of the data has three components:
- While initializing reactive data
data
throughdefineReactive
Method (the core isObject.defineProperty
) will bedata.forProp
becomegetter
和setter
When accessedgetter
Collection dependencies are triggered when they need to be changedsetter
Notifications that depend on this datawatcher
The update; - Initialization of reactive data
computed
The logic of:- 2.1 Create one for each calculated property
watcher
, and createWatcher
ClassexpOrFn
That is, a function that requires a value, which is a method that is declared when evaluating attributes, as in the example above:forPatchComputed () { return this.forProp.a + 'reject 996!!!' }
; - 2.2 Calculated attributes are
lazy watcher
That is, the evaluated property is only evaluated when it is accessed; - 2.3 When is it evaluated? By the time I’m interviewed,
forPatchComputed
Is the template corresponding to the root instanceRender function
We’ll take it when we execute itforPatchComputed
The corresponding value, then evaluated;
- 2.1 Create one for each calculated property
- Modify the
data.forProp.a
The triggersetter
And the frontgetter
Three are knownwatcher
Depending on thisforProp
At this point, notify them of the three updates;
Who is responsible for collecting dependent Watcher and notifying watcher of updates? Dep class, which creates an instance of Dep for each data during responsive initialization. Dep. denpend collection relies on Watcher, and dep.notify notifyWatcher of updates. The watcher update is implemented with the watcher.update() method;
function defineRective () {
const dep = new Dep();
Object.defineProperty(target, key {
get () {
if (Dep.target) dep.depend()
}
set () {
dep.notify()
}
})
}
Copy the code
Click button# BTN to trigger the setter by modifying this.forprop.a to enter the setter:
3.2 Dep. Prototype. Notify
export default class Dep {
// Zoom watcher into the dependency list for responsive data
depend () {
if (Dep.target) {
// Dep.target is set in the getter for reactive data and the value is watcher instance
Dep.target.addDep(this)
}
}
notify () {
// stabilize the subscriber list first
const subs = this.subs.slice()
// Go through the watcher stored in the DEP and execute watcher.update()
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update()
}
}
}
Copy the code
After clicking the button to debug the breakpoint, go to dep.notify and you will find three watcher in this.subs:
- The first one is forPatchComputed this
Calculate the property watcher
As shown in figure
2. The second isdiv#app
Corresponding to the root instance templateRender the watcher
:
- The third is
<some-com />
Custom componentRender the watcher
:
3.3 Wather. Prototype. The update
export default class Watcher {
constructor (.) {}
update () {
if (this.lazy) {
// Lazy execution of watcher goes here
// Set dirty to true,
// When the getter for the calculated property is accessed
// Triggers a recalculation of the result of the computed callback function
this.dirty = true
} else if (this.sync) {
this.run()
} else {
// Update is usually in here,
// Put watcher into the watcher queue,
// Then update the queue asynchronously
queueWatcher(this)}}}Copy the code
3.3.1 Calculate the update of attributes
3.3.2 Render watcher update
QueueWatcher is an important one, and we’ll give it a separate article;
Four,
As the first part of the patch phase, this essay mainly does the following work:
- To modify the
test.html
Added a function to modify reactive databutton#btn
Element, and bind click event modificationdata.forProp.a
; - The whole responsive process is reorganized, including the process of collecting, modifying data and distributing updates. And make it clear
Watcher
,Dep
And the dependent and dependent relationships among responsive data as well as the collaboration process among them; - By modifying the
this.forProp.a
Into thedep.notify()
“And then saw actionCalculate attribute
thelazy watcher
和Ordinary watcher
在watcher.update()
Different approaches in the method:-
3.1 Lazy watcher sets this.dirty to true; This invalidates the cache of computed attributes, and it reevaluates them when they are accessed again, a process that we discussed in detail in Watcher about computed caching;
-
3.2 Ordinary watcher including rendering watcher and user Watcher will execute queueWatcher method for asynchronous queue update;
-