DEV Community

loading...

What is the Virtual DOM? (Let's build it!)

Siddharth
13. Coding for a hobby
・3 min read

You might have heard of the Virtual DOM (and also the Shadow DOM). You may have even used it (JSX is basically sugar for the VDOM). If you want to learn more about it, you've come to the right place!

In this tutorial, I am giong to show you what a Virtual DOM is, and (probably in the next part of this series) show you how we can implement our own. So let's go!

What is a Virtual DOM?

DOM Manipulation is really heavy. The difference may seem small when doing it once (about ~0.4ms difference between assigning a property to an object) but it adds up over time.

// Assigning a property to an object 1000 times
let obj = {};
console.time("obj");
for (let i = 0; i < 1000; i++) {
  obj[i] = i;
}
console.timeEnd("obj");

// Manipulating dom 1000 times
console.time("dom");
for (let i = 0; i < 1000; i++) {
  document.querySelector(".some-element").innerHTML += i;
}
console.timeEnd("dom");
Enter fullscreen mode Exit fullscreen mode

When I ran the above snippet, I found that the first loop took about ~3ms while the second one took ~41ms.

Now let's take a real life example.

function generateList(list) {
    let ul = document.createElement('ul');
    document.getElementByClassName('.fruits').appendChild(ul);

    fruits.forEach(function (item) {
        let li = document.createElement('li');
        ul.appendChild(li);
        li.innerHTML += item;
    });

    return ul;
}

document.querySelector("ul.some-selector").innerHTML = generateList(["Banana", "Apple", "Orange"])
Enter fullscreen mode Exit fullscreen mode

So far so good. Now, if the array changes and we have to re-render, we do this:

document.querySelector("ul.some-selector").innerHTML = generateList(["Banana", "Apple", "Mango"])
Enter fullscreen mode Exit fullscreen mode

See what's going wrong?

Even though only one element has to be changed, we change the whole thing because we are lazy

That's why the Virtual DOM was created.

I know you have been waiting for long, so let's get to the point.

What is the Virtual DOM?

The Virtual DOM is the representation of the DOM as an object. So if you have the following HTML:

<div class="contents">
    <p>Text here</p>
    <p>Some other <b>Bold</b> content</p>
</div>
Enter fullscreen mode Exit fullscreen mode

It can be written as the following VDOM object:

let vdom = {
    tag: "div",
    props: { class: 'contents' },
    children: [
        {
            tag: "p",
            children: "Text here"
        },
        {
            tag: "p",
            children: ["Some other ", { tag: "b", children: "Bold" }, " content"]
        }

    ]
}
Enter fullscreen mode Exit fullscreen mode

Note that there might be more properties in real life and this is a simplified version.

I'm pretty sure that was self explanatory, especially if you have used React. If not:

  • The VDOM is basically an object with
    • A property called tag (sometimes also called type) which is basically the tag's name
    • A property named props which contains all props
    • A property named children which is either
    • A string if the contents are just text
    • An array of VDOMs if the contents contain elements

We use the VDOM like so:

  • We make a change to the VDOM instead of the DOM
  • A function checks all the differences between the DOM and the VDOM and changes only what has really changed
  • The VDOM which has just been used for changing stuff is marked as the latest change, so that we can just compare the VDOMs next time which saves even more

What are the benefits?

I'm pretty sure you already now, but here's a practical example. Let's take our previous generateList function and improve it:

function generateList(list) {
    // VDOM generating stuff which I will explain later...
}

patch(oldUL, generateList(["Banana", "Apple", "Orange"]));
Enter fullscreen mode Exit fullscreen mode

Don't mind the patch function, it basically appends the changes to the DOM.

Now when we change the DOM again in the future:

patch(oldUL, generateList(["Banana", "Apple", "Mango"]));
Enter fullscreen mode Exit fullscreen mode

The patch function finds out that only the third li has changed and only the third li is changed instead of changing all three elements

That's all for what the VDOM is, and in the next part I will show you how we can implement the VDOM

Discussion (17)

Collapse
alimansoorcreate profile image
Syed Ali Mansoor

This is such a great article! I had trouble understanding the VDOM but you made it really clear and simple to follow. Looking forward to the next part! ✌️

Collapse
siddharthshyniben profile image
Siddharth Author

Thanks! The next part might come out in 2 days

Collapse
sargalias profile image
Spyros Argalias

Hey, I enjoyed the article. I also agree with the points you raised. Thanks for the good content :).

Nevertheless, I just want to point some things out that I feel are minor issues in the article.

In the first snippet of code presented. The tests don't seem fair. For the object, i is being set every time, not appended to. However, for innerHTML, i is being appended. This makes the measurement far slower. This is both because of layout thrashing, but also because the resulting string is huge (2,890 digits long). However, the main point still applies. When I tested just setting the value innerHTML, it was about 20 times slower than the operation on the object.

Also, the code snippet with the function generateList doesn't seem to work. I tried created sufficient HTML for it to run, but got a few errors.

Anyway, I still enjoyed the article overall. Keep it up :).

Collapse
siddharthshyniben profile image
Siddharth Author

I was just looking for a quick and easy way to show you stuff and I didn't actually take the time to test it too much. Thanks for pointing those out!

Collapse
sargalias profile image
Spyros Argalias

Yeah I gotcha. That's all good, as I said I still think it's a great article :). Yeah I was nitpicking a bit because I like actually running through the examples for more clarity :)

Thread Thread
siddharthshyniben profile image
Siddharth Author

Me too, but not on my articles πŸ˜‚

Collapse
rajatetc profile image
Rajat Gupta

Very insightful! Waiting for the next part.

Collapse
siddharthshyniben profile image
Siddharth Author

Thanks! The next part might come out in 2 days or maybe tomorrow

Collapse
siddharthshyniben profile image
Siddharth Author

Look at these reactions, I am absolutely mind blown("!".repeat(Number.MAX_SAFE_INTEGER))

(I could do that forever)

Collapse
madza profile image
Madza

How do you like Svelte's aproach, avoiding it entirely? πŸ‘€

Collapse
chrisczopp profile image
chris-czopp

Yeah, Solid also uses build-time DOM diffing so we have at least two projects which prove it can be done. I think Virtual DOM did loads of good for the industry like popularised declarative UI development. However, if the runtime housekeeping like DOM diffing can be done at build-time, then I think it's no-brainer to consider these tools.

Collapse
madza profile image
Madza

Good take πŸ‘

Collapse
siddharthshyniben profile image
Siddharth Author • Edited

I've never got the time to check it out, but I will in the (I hope) near future.

Update: WOW! Svelte has got a really good idea.

Collapse
profesorval profile image
Aaron Professorval

Great article!

Collapse
timhuang profile image
Timothy Huang

Performance is important. Thank you.

Collapse
siddharthshyniben profile image
Siddharth Author

The second part is out! (Was out earlier but I forgot to make it a series πŸ˜…)