This is the first day of my participation in Gwen Challenge
This article is a study note about virtual DOM and diff algorithm, the purpose is to better understand the underlying principle of Vue, the length is long, so it is divided into several chapters, will be updated in the future. Previous content portal: virtual DOM and DiFF Algorithm-01 virtual DOM and DiFF Algorithm-02
Following on from the previous two articles, this article starts with a refined comparison of oldVnode and newVnode when they are the same node.
Diff handles old and new nodes as the same node
Analysis of the
In the refined comparison part, we continue to draw the flow chart (note: in the diff algorithm implemented by hand, the children attribute and text attribute in the virtual node are mutually exclusive, and only one of them has a value).
In fact, the main problem is whether the text and children attributes of the old and new nodes have values in 4 (2×2) cases. When the new node text has values, the old node text has values or children have values. The innerText of the actual DOM of the old node is assigned directly, so there are only three cases:
- The text property of the new node has a value
- It doesn’t matter what the text and children properties of the old node are, we just assign the innerText, right
- The children property of the new node has a value
- The text property of the old node has a value
- The children property of the old node has a value
The new node text has a value or the text of the old node has a value
Now I start to write the two cases 1 and 2 analyzed above, and then I create patchvNode.js as follows:
// patchVnode.js
import creatElement from './creatElement.js'
import updateChildren from './updateChildren.js'
// Handle the case that the old and new virtual nodes are the same node
export default (oldVnode, newVnode) => {
// Whether oldVnode and newVnode are the same object in memory
if (oldVnode === newVnode) return
// The text property of newVnode has no value
if(newVnode.text ! = =undefined && (newVnode.children === undefined || newVnode.children.length === 0)) {
/ / a text
// Whether the text values of the old and new virtual nodes are the same
if(newVnode.text ! == oldVnode.text) {Elm is the real DOM of the old virtual node
oldVnode.elm.innerText = newVnode.text
}
} else {
// No text (newvnode.children has a value)
// Check whether the old node has a value for children or text
if(oldVnode.text ! = =undefined && (oldVnode.children === undefined || oldVnode.children.length === 0)) {
// The text property of the old node has a value, the children property of the new node has a value
oldVnode.elm.innerHTML = ' '
newVnode.children.forEach(item= > {
const newDom = creatElement(item)
oldVnode.elm.appendChild(newDom)
})
} else {
// Both old and new nodes have values for the children attribute
updateChildren(oldVnode.elm, oldVnode.children, newVnode.children) // Explain later}}}Copy the code
Introduce patchvNode.js where patch.js handles old and new as the same node
if (oldVnode.sel === newVnode.sel && oldVnode.key === newVnode.key) {
// Same node
patchVnode(oldVnode, newVnode)
}
Copy the code
Both the old and new nodes have values for the children attribute
In the third case of the above analysis, when we compare each child virtual node in the children of the old and new nodes, these nodes need to have the key attribute defined, otherwise they will be judged as the same node if they are not defined as undefined. So let’s add the key attribute that was omitted from the previous generation of virtual nodes:
// vnode.js
export default (sel, data, children, text, elm) => {
const { key } = data
return { sel, data, children, text, elm, key }
}
Copy the code
Four hit lookups
To deal with the case that both the old and new nodes have values of children, the classic diff algorithm optimization strategy is used: four matching look-ups
- The old and the new
- New queen and old queen
- The new queen and the old one
- New before and old after
These four kinds of hit judgment are carried out according to the order of 1234. Once a hit, the next hit will not be carried out, but the corresponding processing will start. If all are lost, use a loop to find. To prepare 4 Pointers, respectively pointing to “old before”, “old after”, “new before”, “new after”, in a while loop statement to judge, while the condition is old before <= old after && new before <= new after; We break out of the while loop when the old pointer comes behind the old or when the new pointer comes behind the new. If the old node completes the loop first, the new node has nodes to be inserted. If the new node completes the loop first, some nodes to be deleted exist in the old node. 1. New front and old front
First of all, the node pointed to by the pointer of the old and the new node is judged to be the same node. It is found that sel is the same and key is the same, both are Li, and match judgment is made. The subsequent judgment is not carried out, and patchVnode function is used to process h(‘li’, {key: ‘A’}, ‘A’) and h(‘li’, {key: ‘A’}, ‘AAA’), then move the old pointer down one bit to change the node to which the pointer points, and move the new pointer down one bit to change the node to which the pointer points, as follows:
We then find that the old and new Pointers point to the same node again, so we move down one bit more each, and so on, until the old and new Pointers move under the old or new Pointers, breaking out of the while. This section is translated into code as follows
if (sameVnode(oldStartVnode, newStartVnode)) {
patchVnode(oldStartVnode, newStartVnode)
if(newStartVnode) newStartVnode.elm = oldStartVnode? .elm// Assign elm to the new node
oldStartVnode = oldCh[++oldStartIdx]
newStartVnode = newCh[++newStartIdx]
}
Copy the code
2. New queen and old queen
First, the new front hits the old front, and then the Pointers move down separately
At this point, the nodes pointed to by the pointer to the new and the old are not the same node, and then it starts to judge whether the new and the old are matched. If they are found, the new and the old move up one bit respectively to change the node pointed by the pointer, as shown in the following figure:
At this point new before > new after, out of the while loop bad
// 2. New queen and old queen
if (sameVnode(oldEndVnode, newEndVnode)) {
patchVnode(oldEndVnode, newEndVnode)
if(newEndVnode) newEndVnode.elm = oldEndVnode? .elm oldEndVnode = oldCh[--oldEndIdx] newEndVnode = newCh[--newEndIdx] }Copy the code
Since there are more illustrations to follow, all of them would be a bit too long, so I’ll share the remaining two hits and what follows in the next post