Eh, not exactly right either. In the jQuery days, the problem is that you needed different procedural code paths to go from one DOM state to another depending on what action you took. For example, adding a row to a list would be `$('.list').html(html)`, removing would be `$('.list :last-child').remove()` and updating one item might be `$('.list #' + id).text(value)`.

Templating engines such as handlebars provide a declarative abstraction that represents how the DOM is supposed to look like given some rules, rather than procedurally specifying how to get from A to B. This is similar to how you write HTML declarative as opposed to how you have to write canvas code procedurally.

Virtual DOM is just an implementation detail of some templating libraries that have the same goal of providing that declarative abstraction. The problem was that popular KVO systems (e.g. Knockout and Ember) were notoriously slow and people were looking for alternative ways to speed up declarative rendering libraries. The community has since learned a lot about performance and is realizing that KVO systems _can_ be performant after all.

The main drawback of KVO systems is that their API bleeds into the data layer because they require you as a developer to manually register data as observable entities. In contrast, virtual DOM works with plain Javascript objects which are much more familiar and easier to manipulate and interop with. A third approach, called dirty checking and popularized by Angular also had the desirable property of working w/ plain js objects, but it was also very slow. Some systems (most notoriously Vue 1) tried to bridge the gap between KVO and POJOs by providing a POJO-looking data layer that has monkeypatched array methods etc that provide observability/reactivity under the hood. Without JS proxies, though, this still left some weird edge such as the ones handled by `Vue.set`/`Vue.delete`. Vue eventually moved to vdom because the way it mounted subcomponents didn't scale for recursive mounts (think comment trees such as the ones in HN or reddit). This is because it had to mount each level to find out what subcomponents needed to be mounted, and as well know, multiple repaints is a big no-no for perf.

With that said, virtual DOM is not perfect either. It's inherently memory intensive and can block the UI in cases with large DOMs and few changes. Various frameworks have various techniques to cope (such as shouldComponentUpdate and friends) but they typically require developer intervention, whereas a KVO system would not suffer from this class of problems to begin with. Another problematic aspect of virtual DOM systems is that they are "naked" js and thus, difficult to optimize as libraries from an algorithmic standpoint. This is why Svelte does better in benchmarks than vdom systems.

TL;DR: if you want to evaluate the performance characteristics of a KVO system such as Radi or Surplus, the main things you should ask about are API lock-in in the data layer and performance of recursive mounts. If you want to evaluate perf of virtual DOM systems, you should ask about diff latency for needle-in-a-haystack scenarios and ease of use for hooks to selectively diff a tree.