What is the Virtual DOM?

Before we talk about the Virtual DOM, let’s first say what is the DOM, why is it needed, and what is the relationship between them

What is the DOM

The Document Object Model (DOM) is a programming interface for HTML and XML documents that parses them into a structured collection of nodes and objects (objects that contain properties and methods). Simply put, DOM is about parsing documents and linking web pages to scripts or programming languages. Refer to the DEFINITION of DOM in MDN for more information

Why do you need the virtual DOM

The main problem with DOM is that it is not optimized for creating dynamic UIs

The DOM API used to be cumbersome to use directly, but libraries like jQuery have been developed to simplify DOM manipulation. But this does not solve the performance problem of a large number of DOM operations. Dynamic DOM creation/destruction is very common in large page/single-page applications (especially now that front-end rendering is common), and we could certainly use trick to optimize performance, but it’s just too painful.

And Virtual DOM is a kind of exploration to solve the problem.

The Virtual DOM is built on top of the DOM and is a layer of DOM-based abstraction that can be understood as a more lightweight pure JavaScript object (tree) describing the DOM (tree).

The nice thing about the virtual DOM is that when the state changes, you don’t have to update the DOM immediately, you just create a virtual tree that describes the DOM, and the virtual DOM inside will figure out how to diff, update the DOM

Snabbdom is a simple implementation of the Virtual DOM. Let’s see how snabbDOM is implemented

Snabbdom preparation

  • First clone snabbDOM on Git, and then observe the code structure of the projectGit clone - b v2.1.0 - the depth = 1 https://github.com/snabbdom/snabbdom.git

We will focus on examples(official examples) and SRC (source code) directories. Pref is a performance test that we won’t discuss.

Snabbdom core

  • Init () sets up the module and creates the patch() function
  • Use the h() function to create JavaScript objects (vNodes) that describe the real DOM
  • Patch () compares the old and new vNodes
  • Update the changed content to the real DOM tree

Let’s look at the implementation of snabbDOM from these aspects

H function

  • Creates a VNode object
  • H function in Vue
new Vue({
  router,
  store,
  render: h= > h(App)
}).$mount('#app')
Copy the code
  • The h function originated in HyperScript and used JavaScript to create hypertext
  • Objective: To figure out how to create vNodes functionally

The above figure is the h function realized in the h.ts file. Through the function overload of TS, the function overload is realized according to different parameter types, and then determine the parameter types to create vNode objects

Vnode function

The h function creates a vnode object by calling the vnode function. Let’s see what the vnode object looks like

In vode.ts, three types are first defined and exported. The vNode implementation function takes five arguments, processes the key separately, finds that the key is passed through data, and finally returns the object defined in the VNode interface.

After seeing the creation of vNode, let’s take a look at the dom rendering process of VNode. Since the process is quite complicated, let’s first look at the patch core function

init

  • The init function is a higher-order function that returns patch after receiving two arguments
  • The init function accepts the modules: inbound and outbound hook functions that need to be executed. DomApi: What API is used to manipulate the DOM, htmlDomApi by default
  • After we initialize the hook function and define some utility functions, we return patch

patch

Analysis of the overall process of patch

  • patch(oldVnode,newVnode)
  • Render the changed content of the new node into the real DOM, and finally return the new node as the old node for next processing
  • Check whether the old and new VNodes are the same (the key and SEL of the nodes are the same)
  • If it is not the same node, delete the previous content and re-render
  • If the node is the same, check whether the new VNode has a text. If the text is different from that of the oldVnode, update the text directly
  • If the new VNode has children, check whether the children have changed

Flow chart of Patch Function

PatchVNode function

When the old and new Vnodes are the same, execute pathNode(oldVnode: VNode, VNode: VNode, insertedVnodeQueue: VNodeQueue). The following flow chart is a simple analysis of patchVode

The function execution process of patchVode is mainly divided into three parts

  1. Trigger the prepatch and Update hook functions
  2. Compare the differences between the old and new VNodes
  3. Trigger the PostPatch hook function

The following flow chart is only discussed for comparing vNode differences

updateChildren

When both the old and new nodes have children and the children are different, the updateChildren function is called, which is also at the heart of the Diff algorithm

The diff algorithm

First we need to understand why diff is used in the virtual DOM.

Rendering the real DOM is expensive, and DOM manipulation can cause browser reordering and redrawing, which can be very performance consuming. The core of diff in the virtual DOM is to use objects to describe the real DOM instead of directly manipulating dom when data changes. When data changes, the location of changes can be found and DOM updates can be minimized to improve performance

So we know that the Diff algorithm doesn’t have any magic, it just looks for the difference between two trees, but it has a lot of ways to look for it, right

  • The first way is to compare every node in the first tree to every node in the second tree. If there are n nodes, search n^2 times

.

  • Snabbdom optimizes the traditional DIff algorithm according to the characteristics of DOM
    • Dom manipulation rarely involves cross-level manipulation of nodes
    • Only peer nodes are compared
    • If the levels are different, delete them and recreate them
    • Nodes at the same level need to be compared only once to reduce the number of comparisons
    • If you have n nodes, you only need to look it up n times

The specific process of comparing child nodes in snabbDOM

At the beginning of comparison and node node comparison, there are four kinds of total

  • Old start/new start

    If old start and new start are sameVnode(same key and SEL)

    • Call patchVnode() to compare and update nodes
    • Move the old start and new start indexes back oldStartIdx++ / oldEndIdx++

    If not sameVnode, start the old end/new end comparison

  • Old end/new end

    If old end and new end are sameVnode(same key and SEL)

    • Call patchVnode() to compare and update nodes
    • Move the old start and new start indexes back oldStartIdx– / oldEndIdx–

    If not, start the old start/new end comparison

  • Old beginning/new end

    If old start and new end are sameVnode(same key and SEL)

    • Call patchVnode() to compare and update nodes
    • Move the oldStartVnode dom element to the right and update the index

    If not, start old end/new start comparison

  • Old end/new beginning

    If sameVnode(same key as SEL)

    • Call patchVnode() to compare and update nodes
    • Move the oldEndVnode dom element to the left and update the index

If none of the above four conditions are satisfied

  1. First, it iterates through the new start node and looks for nodes with the same key value in the old node array.
  2. If not, create a new DOM element and insert it at the front
  3. If it is found and the sel attribute is judged to be the same, if so, the old node will be copied to elmToMove, and then patchVNode will be called to compare the nodes, and then the DOM node corresponding to elmToMove will be moved to the front

—————— after the loop ends

  • When all child nodes of the old node are traversed first, the new node is left. Insert the remaining nodes to the right in batches
  • If all child nodes of the new node are traversed first, the remaining old nodes are available. Delete the remaining old nodes