This is the sixth day of my participation in the More text Challenge. For details, see more text Challenge

The title was inspired in the comments section:

What is the Virtual DOM

What is the virtual DOM? In short, the virtual DOM is a tree structure that simulates the real DOM, and the tree structure contains the information of the whole DOM structure.

Normally, the real DOM looks like this:

The virtual DOM is like this, containing real DOM information such as tag name, tag attribute, and child node:

Why use the virtual DOM

The virtual DOM is a tree structure that simulates the real DOM, so why use the virtual DOM? What are the drawbacks of working directly with the DOM?

Direct manipulation of the DOM has no disadvantages, but frequent manipulation of the DOM has great disadvantages, because manipulation of the DOM will cause rearrangement. Frequent manipulation of the DOM will cause frequent rearrangement of the browser, resulting in page stashing.

The general flow of browser rendering is as follows:

  1. Parse HTML documents and build DOM trees;
  2. Parsing CSS attributes, building CSSOM tree;
  3. Combine DOM tree and CSSOM tree to build render tree.
  4. Layout based on the Render tree, calculate the geometry of each node (rearrange);
  5. Draw each node on the screen (redraw);

A reorder (also called reflow or reflow) is when the layout property of a DOM node is changed, the property is recalculated and the browser redraws the corresponding element (step 4 above).

Every node in the DOM Tree has a reflow method, and a node’s reflow is likely to result in a child node’s reflow, or even a parent’s or sibling’s reflow.

Therefore, in order to improve performance, we should minimize DOM operations.

1. Reduce DOM operations

When a table needs to be sorted, you can select a sorting method such as date of birth and gender. When you select a sorting method, the table will be resorted according to the sorting method.

  • Real DOM: The sorting operation needs to delete all the DOM trees in the table and create a new one.
  • Virtual DOM: Diff algorithm is used to get the part that needs to be modified, and only DOM nodes that need to be modified are updated;

As can be seen from the above, virtual DOM helps us greatly reduce DOM operations through diff algorithm.

2. Functional UI programming

On the other hand, the virtual DOM provides us with a functional approach to programming that makes code more readable and maintainable.

Iii. Realization principle of virtual DOM

Note: The implementation principle of virtual DOM in this chapter is not a reference to React source code, but a reference to simple-virtual-DOM. You can simply understand the implementation principle of virtual DOM through this chapter. Virtual DOM implementation in React can be viewed in the React official website Virtual DOM and kernel.

The virtual DOM is implemented through the following steps:

  1. Build a virtual DOM tree;
  2. Compare the differences between old and new virtual DOM trees;
  3. Update the real DOM;

1. Build the virtual DOM

Simulate the real DOM tree, build the virtual DOM tree structure, including tagName tagName, attribute object props, child node children, child node count and other attributes.

function Element (tagName, props = {}, children = []) {
  / / tag name
  this.tagName = tagName
  // Attribute object
  this.props = props
  / / child nodes
  this.children = children
  / / the key symbol
  const { key = void Awesome! } = this.props
  this.key = key

  // Number of child nodes
  let count = 0
  this.children.forEach((child, index) = > {
    if (child instanceof Element) {
      count += child.count
    }
    count++
  })
  this.count = count
}
Copy the code

Create a virtual DOM object:

console.log(el('div', {'id': 'container'}, [
  el('h1', {style: 'color: red'},'simple virtal dom']]))Copy the code

The generated virtual DOM object is shown as follows:

To convert the virtual DOM to the real DOM:

Element.prototype.render = function () {
  const el = document.createElement(this.tagName)
  const props = this.props

  for (const propName in props) {
    const propValue = props[propName]
    _.setAttr(el, propName, propValue)
  }

  this.children.forEach((child) = > {
    let childEl

    if (child instanceof Element) {
      childEl = child.render()
    } else {
      childEl = document.createTextNode(child)
    }
    el.appendChild(childEl)
  })

  return el
}
Copy the code

Fill in the page:

document.body.appendChild(el('div', {'id': 'container'}, [
  el('h1', {style: 'color: red'},'simple virtal dom'])
  ]).render())
Copy the code

The effect is as follows:

2. Compare the differences between the two virtual DOM trees

When the data is updated, the old and new virtual DOM trees need to be compared.

  1. If both the old and new nodes are strings, replace them directly.
if (_.isString(oldNode) && _.isString(newNode)) {
    if(newNode ! == oldNode) { currentPatch.push({type: patch.TEXT, content: newNode })
    }
  // Nodes are the same, diff old node's props and children
  }
Copy the code
  1. When the name and key of the new node are equal, compare the attribute Props and the child node children.
if (
  oldNode.tagName === newNode.tagName &&
  oldNode.key === newNode.key
) {
    // Diff props
    var propsPatches = diffProps(oldNode, newNode)
    if (propsPatches) {
      currentPatch.push({ type: patch.PROPS, props: propsPatches })
    }
    // Diff children. If the node has a `ignore` property, do not diff children
    if(! isIgnoreChildren(newNode)) { diffChildren( oldNode.children, newNode.children, index, patches, currentPatch ) } }Copy the code
  1. If the new node exists and has a different label name or key from the old node, replace the new node with the old node.
currentPatch.push({
    type: PATCH_KEY.REPLACE, 
    node: newNode
})
Copy the code

In summary, the virtual DOM Diff only between layers, replacing the node and its children if the tags are different.

Try comparing the virtual DOM as follows:

function renderTree () {
  return el('div', {'id': 'container'}, [
          el('h1', {style: 'color: red'},'simple virtal dom']),
          el('p'['the count is :' + Math.random()])
        ])
}

let tree = renderTree()

setTimeout(() = > {
    const newTree = renderTree()
    const patches = diff(tree, newTree)
    console.log(patches)
}, 2000)
Copy the code

The comparison difference is that the text node of the P label changes, and the output result is shown as follows:

3. Minimize changes to the real DOM

The final step is to modify the real DOM based on the DIff results.

The real DOM tree is traversed. If the DOM node has diff, the DOM node is processed according to the DIFF type. If the DOM node does not have DIff, the child nodes are traversed until the traversal is complete.

Note: React is better. See React Fiber for details.

function patch (node, patches) {
  var walker = {index: 0}
  dfsWalk(node, walker, patches)
}

function dfsWalk (node, walker, patches) {
  var currentPatches = patches[walker.index]

  var len = node.childNodes
    ? node.childNodes.length
    : 0
  for (var i = 0; i < len; i++) {
    var child = node.childNodes[i]
    walker.index++
    dfsWalk(child, walker, patches)
  }

  if (currentPatches) {
    applyPatches(node, currentPatches)
  }
}
Copy the code

Try to update the real DOM with the following code:

function renderTree () {
  return el('div', {'id': 'container'}, [
          el('h1', {style: 'color: red'},'simple virtal dom']),
          el('p'['the count is :' + Math.random()])
        ])
}

let tree = renderTree()
const root = tree.render()
document.body.appendChild(root)

setTimeout(() = > {
  const newTree = renderTree()
  const patches = diff(tree, newTree)
  patch(root, patches)
  tree = newTree
}, 2000)
Copy the code

The effect is as follows:

As you can see above, the real DOM has been successfully updated.

Four,

This paper describes virtual DOM from three perspectives: what is virtual DOM, why to use virtual DOM, and the implementation principles of virtual DOM.

By simulating the tree structure of the real DOM, the virtual DOM collects a large number of DOM operations, and minimizes modifications to the real DOM through the DIff algorithm, so as to reduce browser rearrangement, improve loading speed, and optimize website performance.

The virtual DOM uses functional programming to make our code look better and happier.

Github source code can be used for practice.

I hope it can help you, thanks for reading ~

Don’t forget to encourage me with a thumbs-up, pen refill ❤️

The resources

  • Analysis of React Virtual DOM

  • What is the virtual DOM

  • Why do you need a virtual DOM?

  • Why is the Virtual DOM fast

  • Page rearrange and redraw

  • Reduce page rearrangements and redraws

  • Repaint and Reflow (2)

  • The Internet says that real DOM is slower, but tests show that it’s faster than React. Why?

  • Implementation principles of the Virtual DOM