What's The Deal With Vue's Virtual DOM?
Anthony Gore | February 21st, 2017 | 2 min read
Many Javascript frameworks like Vue, React and Ember implement a "virtual DOM".
While it sounds like something from a sci-fi, its main purpose is to increase the speed and efficiency of DOM updates. It offers some additional benefits as well.
Reminding ourselves what the DOM actually is
We tend think of the DOM as the HTML document it represents. But actually the DOM is a tree-like data structure that comes into existence once an HTML document has been parsed by the browser.
The browser paints the DOM to the screen and will repaint it in response to user actions (e.g. mouse clicks) and updates via its API from your Javascript scripts e.g. document.createElement
.
It’s expensive to update the DOM
When we use Javascript to make a change to our page, the browser has to do some work to find the required DOM nodes and make the change e.g.
// #myId could be anywhere in the document, which may have thousands of nodes!
document.getElementById('myId').appendChild(myNewNode);
In modern apps there can be thousands of nodes in the DOM, and so updates can be computationally expensive. It’s inevitable that small, frequent updates will slow the page down.
What is a virtual DOM?
The DOM can be represented as a data structure in Javascript, too. Here is pseudo-code of how a DOM node could be represented:
// An unordered list represented as Javascript
let domNode = {
tag: 'ul',
attributes: { id: 'myId' },
children: [
// where the LI's would go
]
};
If we call that a "virtual" DOM node, then the complete structure of DOM nodes would make up our virtual DOM.
But why do this?
It’s not very expensive to update virtual nodes.
// This might be how we update the virtual DOM
domNode.children.push('<ul>Item 3</ul>');
If we use a virtual DOM, rather than our code directly calling the DOM API with methods like .getElementById
to make updates, the code will make changes just to the JS object, which is cheap.
Then, when it’s time to get the real DOM in sync with the changes we’ve made, an efficient updating function is used:
// This function would call the DOM API and make changes
// to the browser's DOM. It would do it in batches and with
// more efficiency than it would with arbitrary updates.
sync(originalDomNode, domNode);
In any one cycle there may be many nodes to update, so batching API calls in this way could reduce a lot of inefficiency.
More than performance
Having a virtual DOM it not just a performance enhancement, it means additional functionality will be possible.
For example, in Vue.js, you can bypass the need for an HTML template or a template property by using a render()
method, which returns virtual nodes:
new Vue({
el: '#app',
data: {
message: 'hello world'
},
render(createElement) {
return createElement(
'div',
{ attrs: { id: 'myId' } },
this.message
);
}
});
Output:
<div id='app'>
<div id='myId'>hello world</div>
</div>
Why do this? There are several possible advantages:
- You get the programmatic power of Javascript. You could create factory-style functions to build your virtual nodes using Javascript’s array methods etc, something that would be more difficult using template syntax.
- You can make your code universal. Since your Vue instance does not really on an HTML file it is also renderable by a server for server-side rendering.
- JSX. Render funtions allow JS extensions like JSX which may be desireable for architecting a component-based app.
About Anthony Gore
If you enjoyed this article, show your support by buying me a coffee. You might also enjoy taking one of my online courses!
Click to load comments...