Forum Moderators: open

Message Too Old, No Replies

Getting a conceptual handle on the Virtual DOM

Why do so many people rave about it?

         

ronin

3:31 pm on Mar 15, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



It's 8 years since React.js launched in 2013 and introduced us all to the concept of a Virtual DOM.

For most of those 8 years, I've been playing catch-up:

- I spent 2013-16 figuring out ES5 (the last two times I tried learning JS were... in 2000 and 2004)
- In late 2016 I also spent three days learning jQuery before realising I was never going to need it
- From late 2018-19 I learned my way around ES2015

I still haven't learned any of the headline front-end JS frameworks / libraries of the 2010s, but I'm in a position to make some progress this year, so I think I'll focus on learning Vue 3.

Vue 3 - much like React - has a Virtual DOM, so here's my question:

What's the big deal about the Virtual DOM?

Over and over again, we're told that by diffing the Virtual DOM the javascript can update only the bits that have actually changed instead of re-rendering the whole DOM and that makes it much faster.

Faster than what?

The last time I checked, when I'm writing ES2015+, if I add an EventListener to a DOM Node which then runs a function, then... only the bits of the DOM that I want to change get updated.

So... what's all this about re-rendering the entire DOM? Who does that?

If no-one does it, what's all the fuss about the Virtual DOM?

lammert

4:32 pm on Mar 15, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



The Virtual DOM sits between the manipulation of the DOM elements and the physical rendering of them on the screen. With the Virtual DOM it is possible to do multiple changes to elements before they are pushed to the visible layer.

How this will change performance depends of the complexity of your scripts. If only a few elements change, writing directly to the DOM will have comparable performance. But if your scripts do a multitude of element changes, and in this process, each single element can change multiple times, it is better to first make all those changes to a Virtual DOM where all the elements only contain the bare minimum of information. When all the manipulation is done, the changed Virtual DOM elements can be pushed in one action to the real DOM resulting in only one big physical re-rendering action on the screen.

NickMNS

4:51 pm on Mar 15, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



The last time I checked, when I'm writing ES2015+, if I add an EventListener to a DOM Node which then runs a function, then... only the bits of the DOM that I want to change get updated.

This is an oversimplification. Conceptually how you change things is more important that what you change, such that even seemingly small change to a single element can cause the entire page to be rendered.

Here is an detailed explanation:
[developers.google.com...]

The other thing you are not considering is buffering. In terms of React and I must assume Vue as well, these frameworks buffer changes to the DOM such as to prevent excessive re-renders.

Now all this may well be overkill if all you want from your page is for a menu to expand, or a button to display some additional content. But it is definitely beneficial if you have a case where you have a lot of dynamic content that frequently updates and changes and you want everything to keep working seamlessly.

ronin

10:19 am on Mar 22, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I've done some more reading around the subject.

This line in Hajime Yamasaki Vukelic's Why Virtual DOM is slower (Apr 2017) probably sums it up for me:

Virtual DOM is, by definition, slower than carefully crafted manual updates, but it gives us a much more convenient API for creating UI.


So, in essence, Virtual DOM appears to be about Developer Experience (DX) as much as anything else.

As such, it's like the third chapter after:

1) Bare-metal DOM manipulation
2) innerHTML

ronin

11:03 am on Mar 22, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Aha. There's a really good code comparison example in Chris Minnick's The Real Benefits of the Virtual DOM in React.js (Apr 2016).

Minnick writes that this vanilla javascript code:


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello JavaScript!</title>

</head>
<body>
<div id="example"></div>
<script>
document.getElementById("example").innerHTML = "<h1>Hello, world!</h1>";
</script>
</body>
</html>


takes 339ms - which is almost a second faster than its React Virtual DOM equivalent (1290ms):


<html>
<head>
<meta charset="UTF-8" />
<title>Hello React!</title>
<script src="build/react.js"></script>
<script src="build/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
</script>
</body>
</html>


But what stands out about that comparison for me is that the vanilla JS example still uses innerHTML.

It's not the case that I never use innerHTML, but I certainly avoid it unless I absolutely need it (and normally I don't) because I'm aware that the parser is slower than simply performing DOM manipulations.

Rather than deploying innerHTML, this is what I would write:


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello JavaScript!</title>

</head>
<body>
<div id="example"></div>
<script>
const example = document.getElementById("example");

const exampleHeading = document.createElement('h1');
exampleHeading.textContent = 'Hello, world!';

example.appendChild(exampleHeading);
</script>
</body>
</html>


Only testing will confirm, but I'm almost certain this is significantly faster than deploying innerHTML.

lammert

11:45 am on Mar 22, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Every simple system can be more efficiently programmed with a lower level programming approach. But with increasing complexity, the use of higher level programming languages and frameworks becomes almost a necessity. That is why assembler language has been abandoned decades ago, despite procedural and object oriented languages producing less efficient code.

Hard HTML coded sites were the norm 25 years ago. Then Perl, ASP and PHP took over to make the server side easier. Now it's the turn for larger frameworks which extend to the client side in the browser.

You can fight windmills or embrace them. It's your choice and your future.

ronin

2:31 pm on Mar 29, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



That's a really good summary of architectural trends.

I absolutely see what you're getting at: over time, efficiency may be sacrificed for ease of maintenance and modification.

You can fight windmills or embrace them.


There's (arguably) a third option: build your own mill.

I've been building (am still building) my own... well it's not quite a windmill, let's maybe call it a watermill.

It's not entirely a front-end library like React, or framework like Vue or compiler like Svelte. Though it's probably more like the third than the other two. It's not entirely like npm or ESModules or WebComponents though it has similarities with those module / component-like structures. It's not entirely like WordPress either, though my frustration with WP was what inspired me to start working on it. It does use JSON extensively and it is intended to be server-side-language agnostic, such that I've developed it in PHP but I am now porting it to Deno and plan, eventually, to write ports in Ruby, Python, etc. It also works entirely client-side, using JS alone.

I was keen to learn more about Virtual DOM in case I was missing something really vital which I ought to giving some thought to. But I've decided that - for now at least - my watermill is not going to need a Virtual DOM.