From jQuery to Virtual DOM: Evolution, Advantages, and the Rise of No‑Virtual‑DOM Frameworks
From jQuery’s imperative DOM hacks to React’s virtual‑DOM abstraction and now to compile‑time, no‑virtual‑DOM frameworks like Svelte and Solid, the front‑end has shifted toward declarative UI, fine‑grained reactivity, and performance‑focused optimizations, while virtual‑DOM remains widely used but increasingly challenged.
Birth of Declarative UI
In the early days of web development, string concatenation and jQuery dominated. jQuery used imperative DOM manipulation, e.g.:
$("ol li").click(function(){})
let li = $("
我是一个li
");
$("ol").append(li);In 2013, Jordan Walke (Facebook) introduced JSX, moving UI code from imperative to declarative style:
// Declare a data list
const Component = (
{data.map(item =>
)}
);Virtual DOM Emergence
"Any problem in computer science can be solved by adding an indirect layer." – David Wheeler
React pioneered the virtual DOM, inserting an intermediate layer between code and the real DOM: code → virtual DOM tree → real DOM tree . The approach was motivated by the performance bottleneck of direct DOM scripting.
Enables functional UI programming and component abstraction.
Cross‑platform: the virtual DOM is just a JavaScript object, usable in mini‑programs, iOS, Android, etc.
Batch updates reduce reflows and repaints (e.g., inserting 100 nodes in one operation).
const fragment = document.createDocumentFragment();
for(let i = 0; i < 1000; i++){
const div = document.createElement('div');
fragment.appendChild(div);
}
// Insert once
const container = document.getElementById('container');
container.appendChild(fragment);Further benefits include lightweight diffing, caching, and avoiding costly DOM queries.
Current State and Criticisms
Some frameworks are moving away from virtual DOM due to its overhead:
Initial render can be slower because of the extra virtual‑DOM computation.
Memory is consumed to keep a virtual tree.
Frequent updates may cause more CPU work than direct DOM manipulation.
Even with optimizations in modern frameworks, the diff‑and‑patch step still adds cost.
Industry Evaluations
Uber heavily uses shouldComponentUpdate to limit renders. React 16 introduced Fiber to prioritize updates and mitigate deep virtual‑DOM traversals. Vue’s author,尤雨溪, discusses breaking virtual‑DOM bottlenecks in Vue 3. Svelte’s creator, Rich Harris, published “Virtual DOM is pure overhead”, arguing that compile‑time conversion eliminates the need for a virtual layer.
Non‑Virtual‑DOM Leaders (2024)
While React and Vue 3 continue to refine virtual‑DOM performance, frameworks that avoid it entirely—Svelte and Solid—are gaining attention.
Svelte
Rich Harris (also author of Rollup) built Svelte to compile declarative code into highly efficient imperative JavaScript, removing the runtime virtual‑DOM cost.
<script>
let count = 0;
function handleClick(){
count += 1;
}
$:{ console.log(`the current count is ${count}`); }
</script>
<div class="x-three-year" on:click={handleClick}>
<div class="no-open" style={{ color: 'blue' }}>{`当前count: ${count}`}</div>
</div>Svelte’s compiler injects $$invalidate calls to track reactive assignments.
function instance($$self, $$props, $$invalidate) {
let count = 0;
function handleClick() { $$invalidate(0, count += 1); }
$$self.$$.update = () => {
if ($$self.$$.dirty & /*count*/ 1) {
$: { console.log(`the current count is ${count}`); }
}
};
return [count, handleClick];
}Vue Vapor Mode
Vue 2 introduced virtual DOM for abstraction. Vue 3 adds compile‑time hints to static nodes, reducing diff work. At the 2022 “稀土掘金开发者大会”, Vue’s creator announced a “Vapor Mode” inspired by Solid, aiming to eliminate virtual DOM by leveraging Vue’s fine‑grained reactivity.
SolidJS
Solid follows a compile‑time approach similar to Svelte but keeps a JSX‑like syntax. Its core is the Signal system, providing fine‑grained reactive primitives.
export function createSignal
(value?, options?) : Signal
{
const s: SignalState
= { value, observers: null, observerSlots: null, comparator: options.equals };
const setter = (value?) => { /* writeSignal logic */ };
return [readSignal.bind(s), setter];
}Signals are read via readSignal , which registers the current Listener as an observer, and written via writeSignal , which schedules updates.
export function readSignal(this: SignalState
| Memo
) {
if (Listener) { /* add observer */ }
return this.value;
}Effects and computations are created with createEffect and createRenderEffect , which internally build a Computation object and push it onto the effect queue.
function createEffect
(fn: EffectFunction
, value?, options?) {
const c = createComputation(fn, value!, false, STALE, options);
Effects ? Effects.push(c) : updateComputation(c);
}Solid’s API discourages destructuring reactive props because shallow copies break tracking; instead, mergeProps and splitProps should be used.
Framework Comparison
Popularity (npm downloads) still favors React, Vue, and Angular, but satisfaction scores show rising interest in non‑virtual‑DOM frameworks.
Performance benchmarks (js‑framework‑benchmark, Chrome 119 on macOS) indicate that Svelte and Solid often outperform React and Vue in raw speed and memory usage, while specialized virtual‑DOM frameworks like ivi and Inferno remain competitive.
"I will admit it was React’s rhetoric about the Virtual DOM’s performance that led me into this space in the first place." – Ryan Carniato
Conclusion
The front‑end landscape has evolved from jQuery’s imperative manipulation to React’s virtual DOM and now to compile‑time, no‑virtual‑DOM solutions like Svelte and Solid. In 2024, virtual DOM remains dominant, yet the trend is toward finer‑grained reactivity and compile‑time optimizations. There is no single “best” technology; the field continuously refines and balances performance, developer experience, and ecosystem support.
NetEase Cloud Music Tech Team
Official account of NetEase Cloud Music Tech Team
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.