Virtual DOM concept

Virtual DOM (Virtual DOM) is a JS abstract representation of THE DOM. They are JS objects that describe the DOM structure and relationships. Various state changes of the application will act on the virtual DOM and eventually map to the DOM.

Vue 1.x has fine-grained data change detection that does not require the virtual DOM, but this fine-grained approach incurs a lot of overhead that is unacceptable for large projects. Therefore, Vue 2.x opted for a medium-grained solution, one Watcher instance per component, so that only components are notified of state changes, and virtual DOM is introduced for comparison and rendering.

As we know, render. Js generates vNodes, whereas in Lifecycle. Js the update method is responsible for updating the DOM and converting the VNode to the real DOM, so let’s look at lifecycle.

instance/lifecycle.js

And we see that the core isvm.__patch__Method, so where does this method come from?

This is going to go back to the very beginning, initialization, in runtime/index.js, and let’s see what we did.

runtime/index.js

Where does the patch function come from? There is a patch.js file in the same directory.

runtime/patch.js

The Patch function is the return value of the project function createPatchFunction and the passed nodeOps and Modules are web platform implementations.

It is clear that the createPatchFunction function comes from the vdom/patch.js file, which is the core of patch.

vdom/patch.js

At the beginning of the file, we see what the author says that patch files are not written in flow due to performance considerations. And it should be mentioned that since this is a DOM tree comparison, there are three cases: add, delete, change.

  • If the old node does not exist, add it
  • If the new node does not exist, delete it
  • If both the old and new nodes exist, diff algorithm (Patch algorithm) is implemented to update them

Patch method

So let’s go back to the patchVnode method to see where diff actually happens.

PatchVnode method

In patchVnode method, some special cases are dealt with at the beginning, that is, asynchronous components and static nodes (without comparison), and then the core code is as follows:

As you can see, comparing two VNodes, there are three types of operations: attribute update, child node update, and text update.

Rules:

  1. Both the old and new nodes have children, so the diff algorithm is applied to the children and the updateChildren method is called.
  2. If the new node has children and the old node does not, clear the text of the old node and add children to it.
  3. If the new node has no children and the old node has children, all children of that node are removed.
  4. When both the old and new nodes have no children, then it’s just text replacement.

Since it is a DOM tree comparison, there are at most child nodes, which means rearranging updateChildren is the most core method.

UpdateChildren method

The main function of updateChildren is to compare the child nodes of the old and new VNodes in an efficient way to obtain the minimum operation patches. Perform a binary to a a relatively is a traditional way, but we use scene, vue doing a special optimization algorithm, because according to the statistics, we can know that two child nodes less happen very big change, more is the fore and aft add elements, remove elements, reverse, etc., in these cases, the fore and aft will always find the same node, Then you don’t need a loop at all. So what does Vue do?

Start with a cursor (variable marker) at the beginning and end of both the old and new nodes, record the cursor position, and then start cross-comparing pairs. These cursors will all move towards the center during the comparison, ending when oldStartIdx > oldEndIdx or newStartIdx > newEndIdx.

Illustration:

Source:

Rule 1

When oldStartVnode and newStartVnode are the same (satisfying sameVnode), patchVnode is directly used and one of the two cursors is moved to the middle to complete a cycle without going through again.

Rule 2

When oldEndVnode and newEndVnode are the same (satisfying sameVnode), patchVnode node is directly made and one of the two cursors is moved to the middle to complete a cycle without going through again.

Rule 3

If oldStartVnode and newEndVnode satisfy sameVnode. Note oldStartVnode has run after oldEndVnode. When patchVnode is being performed, move oldStartVnode to the end of oldEndVnode and move one of the two cursors to the middle.

Rule 4

If oldEndVnode and newStartVnode meet sameVnode, it indicates that oldEndVnode runs before oldStartVnode, and oldEndVnode should be moved to the front of oldStartVnode when patchVnode is performed. And move the two cursors one to the middle.

Rule 5

If none of the preceding conditions are met, find the same node (sameVnode) as newStartVnode in the old node.

  1. If patchVnode is executed, move the DOM corresponding to the found node to the front of oldStartVnode.

0. If not, createElm is called to create a new DOM node, which is inserted in front of oldStartVnode. !

Source:

Rule 6

At the end of the loop, we need to process the remaining nodes.

When oldStartIdx > oldEndIdx ends, the old VNode has been traversed, but the new node has not. Insert the DOM of the remaining VNodes into the real DOM. Call addVnodes (batch call createElm interface).

If newStartIdx > newEndIdx is displayed, the new vNodes have been traversed, but the old nodes are still available. Delete the vNodes in batches.

Source:

supplement

1

2

When you recursively compare, it’s depth-first.

3