One, foreword

React and Vue, the two most popular front-end frameworks, both use Virtual DOM technology to improve page rendering efficiency. So, what is the Virtual DOM? How does it improve page rendering efficiency? This series of articles will walk you through the Virtual DOM creation process and implement a simple Diff algorithm to update the page. The content of this article is separate from any front-end framework, only the purest Virtual DOM. Type words too tired, below Virtual DOM will be used VD.

This is the first article in a series that will take you deeper into the mysteries of VD.

What is VD

In essence, VD is a simple JS object that contains at least tag, props, and children. Different frameworks name these three attributes a little differently, but the meaning is the same. These are tag names (tag), attributes (props), and child element objects (children). Here is a typical VD object example:

{
    tag: "div".props: {},
    children: [
        "Hello World", 
        {
            tag: "ul".props: {},
            children: [{
                tag: "li".props: {
                    id: 1.class: "li-1"
                },
                children: ["The first".1]}]}Copy the code

VD has a one-to-one correspondence with the DOM object, and the VD above is generated by the following HTML

<div>
    Hello World
    <ul>
        <li id="1" class="li-1">1</li>
    </ul>
</div>
Copy the code

A DOM object, such as Li, is described by tag(li), props({id: 1, class: “li-1″}), and children([” digit “, 1]).

Three, why VD

With VD, you can effectively reduce the page rendering times, thereby improving the rendering efficiency. Let’s start with the next page update which usually goes through several stages.

From the above example, you can see that the page is rendered in the following three stages:

  • JS calculation
  • Generate render tree
  • Draw the page

In this example, the JS calculation took 691 ms, the render tree was generated in 578 ms, and the drawing took 73 ms. If you can effectively reduce the amount of time it takes to generate render trees and draw, the efficiency of updating pages will increase. By comparing VD, we can combine multiple operations into one batch operation, which reduces the number of DOM rearrangements, thus reducing the time it takes to generate render trees and draw. How to update the DOM more efficiently with VD is an interesting topic that will be covered in another article at a later date.

How to map VD to real DOM

Let’s start with how we make VD. With the HELP of the JSX compiler, you can convert the HTML in a file to the form of a function, which can then be used to generate VD. Look at this example:

function render() {
    return (
        <div>
            Hello World
            <ul>
                <li id="1" class="li-1">1</li>
            </ul>
        </div>
    );
}
Copy the code

This function, compiled by JSX, outputs the following:

function render() {
    return h(
        'div'.null.'Hello World',
        h(
            'ul'.null,
            h(
                'li',
                { id: '1'.'class': 'li-1' },
                '\u7B2C1'))); }Copy the code

So h here is a function, you can call it anything. This name is configured via Babel:

/ /. Babelrc file
{
  "plugins": [["transform-react-jsx", {
      "pragma": "h"    // You can configure any name here}}]]Copy the code

Now, all we need to do is define h, and we can construct VD

function flatten(arr) {
    return [].concat.apply([], arr);
}

function h(tag, props, ... children) {
    return {
        tag, 
        props: props || {}, 
        children: flatten(children) || []
    };
}
Copy the code

H takes three or more arguments, the first two of which are the name of the label, the first of which is the attribute object, and the other arguments from the third are children. The children element might be in the form of an array that needs to be deconstructed one level. Such as:

function render() {
    return (
        <ul>
            <li>0</li>
            {
                [1, 2, 3].map( i => (
                    <li>{i}</li>))}</ul>
    );
}

// JSX is compiled
function render() {
    return h(
        'ul'.null,
        h(
            'li'.null.'0'
        ),
        /* * We need to deconstruct the following array into the children array */
        [1.2.3].map(i= > h(
            'li'.null,
            i
        ))
    );
}
Copy the code

Continue with the previous example. After executing h, we end up with the following VD object:

{
    tag: "div".props: {},
    children: [
        "Hello World", 
        {
            tag: "ul".props: {},
            children: [{
                tag: "li".props: {
                    id: 1.class: "li-1"
                },
                children: ["The first".1]}]}Copy the code

Next, generate the actual DOM by iterating through the VD object

// Create a DOM element
function createElement(vdom) {
    // If vDOM is a string or a number, create a text node, such as "Hello World"
    if (typeof vdom === 'string' || typeof vdom === 'number') {
        return doc.createTextNode(vdom);
    }

    const {tag, props, children} = vdom;

    // 1. Create an element
    const element = doc.createElement(tag);

    // 2. Attribute assignment
    setProps(element, props);

    // 3. Create child elements
    // appendChild checks if the current this object is a DOM object at execution, so bind it
    children.map(createElement)
            .forEach(element.appendChild.bind(element));

    return element;
}

// Attribute assignment
function setProps(element, props) {
    for (let key inprops) { element.setAttribute(key, props[key]); }}Copy the code

When the createElement function is complete, the DOM element is created and displayed on the page. .

Five, the summary

This article introduced the basic concepts of VD and showed you how to use JSX to compile HTML tags, generate VD, and then create the real DOM. The next article will implement a simple VD Diff algorithm to find the differences between the two VDS and map the updated elements into the DOM.

P.S.: See the full code here: Code

Reference links:

  • The Inner Workings Of Virtual DOM
  • JSX parsing and DOM rendering