What is a diff? Diff is to compare two trees, render will generate two trees, a new tree newVnode, an old tree oldVnode, and then compare and update the two trees to find the difference is diff, full name difference, in Vue diff algorithm is completed by the patch function, So it is sometimes called patch algorithm

⏳ the timing of diff

When did diff happen? Of course we can say that diff occurs during data updates, because data updates run the render function to get the virtual DOM tree, and then the page is rerendered.

When a component is created and properties or data on which the component depends change, a function (updateComponent in the following code) is run that does two things:

  • run_renderCreate a new virtual DOM tree (vNode tree)
  • run_updata, pass in the root node of the virtual DOM tree generated by _render, compare the old and new trees, and finally complete the update of the real DOM

The core code is as follows, different from the original code, but almost the same.

// Vue constructor
function Vue(){
  / /... Other code
  var updateComponent = () = > {
    this._update(this._render());
  }
  new Watcher(updateComponent);
  / /... Other code
}
Copy the code

diffTakes place in_updateDuring the execution of a function

In the code, the _render function is first called to get the virtual DOM root node, and then passed into the _update function. When updateComponent is passed into Watcher, Watcher can monitor the process of function execution, monitor which responsive data is used during function execution and collect dependencies. For watcher, check out my last article, which took you through the responsive principles of the VUe2

What is the 🔨 _update function doing?

The _update function receives a vonde argument, which is the newly generated virtual DOM tree, and the _update function retrives the old virtual DOM tree from the current component’s _vNode property. The _update function first reassigns the component’s _vNode property to point to the new tree

In simple code:

function update(vnode){
    / / vnode new trees
    / / this. _vnode old tree
    this._vnode = vnode
}
Copy the code

If you only consider updating the virtual DOM tree, this step is already done, but the ultimate goal is to update the page, so you use diff for tree node comparison, so you can save the old tree oldVnode for comparison

In simple code:

 <body>
    <div id="app"></div>
    <script src="./vue.js"></script>
    <script>
      const vm = new Vue({
        el: "#app"});function update(vnode) {
        / / vnode new trees
        / / this. _vnode old tree
        
        let oldVnode = vm._vnode; // Save the old tree
        
        this._vnode = vnode; // Update the new tree
      }
    </script>
  </body>
Copy the code

Compare oldVnode and vNode. The purpose of the comparison is to update the real DOM

Next, it checks whether the old tree oldVnode exists:

  • Does not exist: indicates that this is the first time to load the component, so through the internal patch function, directly traverses the new tree, generates real DOM for each node, and then mounts to each nodeelmOn the properties

In simple code:

<body>
    <div id="app"></div>
    <script src="./vue.js"></script>
    <script>
      const vm = new Vue({
        el: "#app"});console.log(vm);

      function update(vnode) {
        / / vnode new trees
        / / this. _vnode old tree
        let oldVnode = vm._vnode; // Save the old tree
        this._vnode = vnode; // Update the new tree

        // If old tree oldVnode does not exist
        if(! oldVnode){this.__patch__(vm.$el,vnode); }}</script>
  </body>
Copy the code
  • Existing: indicates that the component has been rendered before, so the internal patch function is used to compare the old and new trees to achieve the following two objectives:
  1. Complete the minimization of all the real DOM
  2. Make the nodes of the new tree correspond to the appropriate real DOM

🙌 Patch function comparison process

Explanation of terms:You will see the following words, which all mean the following

1. “Same” : the label type and key value of the two virtual nodes are the same, but the input element depends on the type attribute. This term, called sameVnode in the VUE source code, is a function that determines whether two virtual nodes are the same node

Example: Whether two virtual node divs are the same

The < div > forensic < / div ><div>The front end of hunter</div>
Copy the code

The tag type is div, and the key can be used in any tag, not only in v-for traversal, but also in any tag. There is no key in the above two divs, so they are undefined, so the tag type and key are the same, regardless of whether the content is the same, it is another node: the text node

<div key="fayi"> forensic < / div ><div key="qdls">The front end of hunter</div>
Copy the code

The two virtual nodes above are different because the key value is different

 <input type="text">
 <input type="radio">
Copy the code

The two virtual nodes above are different because input looks not only at the key value and label type, but also at whether the type is the same

2. “New Element” : it means to create a real DOM element according to the information provided by a virtual node and mount it to the ELM attribute of the virtual node

3. “Destroy elements” : means: vnode.elm.remove()

4. Update: A comparison update is performed on two virtual nodes only when the two virtual nodes are the same. The process will be described later.

5. Compare child nodes: Compares the child nodes of two virtual nodes. Details are described later

Detailed process

Root node comparison

The patch function first compares the root node

If two nodes:

  • If “Same” is displayed, the Update process is displayed
  1. Assign the real DOM of the old node to the new node:newVnode.elm = oldVnode.elemOld nodes are collected by the garbage collection mechanism
  2. Compare the properties of the new node with those of the old node and update them to the real DOM with changes
  3. The processing of the new and old nodes is completed, and the “compare child nodes” is started.
  • Not the same
  1. New node recursion, “New element”
  2. Old nodes “destroy elements”

Contrast child node

The virtual DOM tree has been completed, so it is left to modify the real DOM. However, the efficiency of modifying the real DOM is time-consuming. The principle of VUE is not to change, and do nothing as much as possible.

  • Try not to do anything

  • Otherwise, try to change only element attributes

  • If not, move elements around instead of deleting and creating them

  • If you have to, delete and create elements

Comparison process:

Photo caption:

  • Yellow circle: indicates the same node type for the old and new child nodes
  • Number: indicates the key value, which is used to distinguish whether the node is the same
  • Blue square: represents the real DOM compared to the old child node
  • Arrow: indicates head pointer and tail pointer respectively

Next, we need to compare the difference between the old child node and the new child node. The goal is to change the real DOM and map the new virtual child node into the real DOM. Vue uses two Pointers to point to the head and tail of the old child node tree

Steps:

  1. First, compare the head pointer of the new tree with that of the old tree to see if the two nodes are the same. First, the real DOM of the old node is assigned to the new node (the real DOM is connected to the new child node), then the properties of the old node are cyclically compared to see if there is any difference, and the changes are updated to the real DOM. Finally, depth-first is adopted (the node of a tree reaches the end, If there are any children, then we’ll assume there are no children. Gray indicates that the processing is complete, and then the two head Pointers move back

  1. Next, continue to compare the two header Pointers to see if the two nodes are the same. Obviously, the two nodes are not the same, because the key value is different, it will not be destroyed when it is different. Delete from create, eat 🍗 calm down! As mentioned in the previous step, try not to manipulate the DOM. It must find the same node, a path to black, and then compare the tail pointer, you can see that the tail pointer is the same, as in the first step: First, the real DOM of the old node is assigned to the new node (the real DOM is connected to the new child node), then the properties of the old and new nodes are cyclically compared, and the changes are updated to the real DOM. Then, the two old and new child nodes are recursively looped to see if there are any children. Finally, the two tail Pointers move forward

  1. And then we go on to the head pointer, and it’s obviously different. What about the tail pointer? It’s not the same, because the key is still different. Then it will compare the head pointer and tail pointer to see if they are the same. It can be seen that the circle 2 head pointer of the old node is the same as the circle 2 tail pointer of the new node, so the operation is the same as the previous two steps.

Here we should note that the real DOM must correspond to the new virtual child node one by one, so in addition to the updated changes, the position should be moved to the back of the old tree tail pointer, and finally the old tree head pointer moves back and the new tree tail pointer moves forward, as shown below:

  1. Continue to compare, new and old head pointer is different, the tail pointer, two different head to tail, and then it will be in a new tree head pointer as a benchmark, recycling old virtual child nodes, see if new trees round 3 exist in old virtual child nodes, exist in which position, after finding for reuse, attachment, there are changes to the dom, real operation is just like the front steps, The real DOM is also doneposition, moves to the front of the old tree head pointer. Then the new tree head pointer continues to move back to circle 9, as shown below:

  1. Continue to compare, the old and new head pointer is different, the tail pointer is different, but the new tree head pointer is the same as the old tree tail pointer, the operation is the same as the previous steps, but still need to move, move to the old tree head pointer. Then the new tree head pointer moves backwards to coincide with the new tree tail pointer, and the old tree tail pointer moves forward to the position of circle 1, as shown below:

  1. Then it uses the new tree head pointer as a reference and loops through the old virtual child node to find if circle 8 exists in the old tree. As can be seen from the figure, circle 8 does not exist in the old tree. At this time, there is really no way to “create a new element”. Then the new tree head pointer continues to move back to circle 2, as shown in the figure below:

  1. Pledge pointer to round 2, the head pointer is no longer effective, so the pointer over the tail pointer, the end of the cycle, from the process we can see that new trees first cycle is completed, but the old tree and the rest of the nodes, it shows that the rest of the nodes in the old tree are should be delete nodes, the corresponding real dom will be removed

Finally, the real DOM is generated. During the whole process, we only create one element, as shown below:

During the interview, we will also be asked questions about the Diff algorithm. The following are the reference answers:

When a component is created or updated, vue performs an internal update function, which uses the render function to generate a virtual DOM tree that compares the old and new dom trees to find the differences, and finally updates to the real DOM in a process called DIff. Vue completes this process internally through a function called patch. In comparison, VUE performs depth-first and peer comparison. At the same level compare to say it won't cross structure comparison In judging whether the two nodes at the same time, the vue is through virtual node key and tag to determine specifically, first of all, comparing the root node if the same the old node associated real dom references on a new node, and then according to the need to update the attribute to true dom, Then compare the child node array; If they are different, all real DOM's are created recursively based on the information of the new node and attached to the corresponding virtual node at the same time, and then the old DOM is removed. When comparing arrays of child nodes, Vue uses two Pointers to each array of child nodes, one to the head and one to the end, and then to the middle for comparison. The purpose of this is to reuse the real DOM as much as possible, and to destroy and create the real DOM as little as possible. If they are the same, go through the same comparison process as the root node, and if they are different, move the real DOM to the appropriate location. And so on, recursively, until the whole tree is compared.Copy the code

😊 ok, above is my share, you can discuss duck ~ in the comments section for other understanding of diff algorithm

I hope you can like 👍 to support oh ~ 😘, I will be more motivated 🤞