cft

Frontend Architectural Patterns: Virtual DOM

A Brief Look at a Helpful Abstraction


user

Bowei Han

3 years ago | 4 min read

What’s a DOM?

The Document Object Model (DOM) is the data structure that a browser uses to represent an HTML file.

DevTools DOM visualization

More specifically, the browser DOM is an object-oriented tree data structure with nodes that contain information about the structure, style, and content of a web page. Think you can memorize the spec?

To represent elements in a meaningful way, each node has methods to:

  • Specify its children.
  • Set custom attributes.
  • Add and remove event listeners.

Although the DOM can be accessed and manipulated with JavaScript, it’s typically implemented as part of the browser engine (think C++). Besides being responsible for parsing HTML into the DOM tree, the browser engine also handles some other relevant tasks:

  • Creating a visual representation of the page — the render tree.
  • Tracking “dirty” DOM nodes to understand when the render tree needs to be updated.
  • Calculating element size and position, a process known as layout or reflow.
  • Physically rendering pixels to the screen, a process known as painting.

These tasks are relevant to the DOM…but feel free to take a detour and dive deeper into how browsers work.

What‘s a Virtual DOM?

A virtual DOM, simply put, is a JavaScript representation of the DOM.

/**
* Sample VDOM Operations
*/
interface VirtualDom {
createElement
updateElement
setProp
removeProp
addEventListeners
markDirty
diff
patch
}

Sample vDOM operations

Image by ElisaRiva from Pixabay
Image by ElisaRiva from Pixabay

Why Bother?

Why would you ever want to reimplement something that’s already native to the browser and written in a faster programming language?

Here are a few reasons:

  1. Manual DOM manipulation can get ugly! Keeping track of previous states and tracing events isn’t easy in a large application. A virtual DOM is essentially a framework on top of the browser DOM; abstracting away the messy details.
  2. Remember how we talked about layout, painting, and updating render trees? The browser tries to do all of this when you update the DOM. If you don’t write your code carefully and use APIs like DocumentFragment, there’s a good chance you’ll accidentally create some performance issues.
  3. Real DOM manipulation requires imperative programming — you repeatedly tell the program how to change and try to make sense of the state. In UI development where state management is a primary concern, it’s much easier to reason about declarative programming — just tell the program what you want to see.
  4. The virtual DOM sits between the browser DOM and the application developer, giving framework developers more control over the rendering cycle. This control paves the way for awesome projects like React Fiber, which takes advantage of React’s virtual DOM and pull-based computation model to slice and dice rendering work over multiple frames.

That being said, keep in mind that the virtual DOM is an abstraction. It doesn’t have the ability to magically outperform the real DOM that it’s built on top of — it just makes it easier for developers to write cleaner applications.

How Would You Implement One?

Let’s dig a little deeper and take a look at Matt Esch’s virtual-dom; an open-source package with 10k+ stars and 3k+ dependents.

Matt-Esch/virtual-dom
Matt-Esch/virtual-dom

You’ll find a few familiar keywords in the project README.md.

Manual DOM manipulation is messy and keeping track of the previous DOM state is hard
virtual-dom is a collection of modules designed to provide a declarative way of representing the DOM for your app

This particular package has three components:

  1. virtual-hyperscript, a domain-specific language for creating virtual trees — used to create an initial DOM tree.
  2. vdom, an algorithm to render and patch the real DOM. This component exposes two methods:
    [1] createElement(tree:VTree): create a real DOM node out of a virtual tree.
    [2] patch(rootNode:DOMNode, patches:PatchObject): apply a set of computed patches to update a real DOM node.
  3. vtree, a difference-finding algorithm that’s able to spit out a minimal set of patches between two virtual trees (think minimum edit distance). These patches can then be used in a vdom::patch.

All you really need to satisfy the base definition of a virtual DOM is [1] an in-memory tree, [2] a way to translate your in-memory tree into real DOM elements, and [3] some algorithm for comparing the previous and new states of your virtual DOM (apparently designing tree diffing algorithms can be pretty fun).

Drawbacks

Virtual DOMs garnered a lot of hype when they were first introduced. Clearly, the React core team was waving a magic wand that could make code cleaner, faster, and cooler.

While I’m a fan of the concept, shipping a runtime-based virtual DOM to the browser definitely has some downsides:

  • Your application bundle needs to be larger to accommodate an entire DOM translation framework.
  • You’ll have to accept that extra computation is needed to perform constant tree diffing and action translation.
  • Holding a representation of the entire page in memory isn’t free.

I think Rich Harris hit the nail on the head when he said that the Virtual DOM is pure overhead.

Virtual DOMs in the wild

Popular Virtual DOMs

Don’t be afraid to write your own! Snabbdom, for example, has less than 200 lines of code. I started writing one in 2018, maybe I’ll get back to it one day…

That’s a Wrap

Virtual DOMs have changed UI development by paving the way for declarative frontend frameworks and cleaner state management. Although they aren’t perfect, I think it’s fair to say that they have been a step in the right direction.

Upvote


user
Created by

Bowei Han


people
Post

Upvote

Downvote

Comment

Bookmark

Share


Related Articles