simoong·blog

Virtual DOM vs. Real DOM — A Hands-On Rendering Performance Comparison

image

Virtual DOM vs. Real DOM — Understanding the Real Performance Difference

When studying frameworks like React and Vue, the concept of Virtual DOM inevitably comes up.

Many articles claim that "Virtual DOM is faster than Real DOM,"

but this is actually only half true.

Today, I'll explain when Virtual DOM is fast and when it's slow,

and how to experience it yourself through experimentation.

--

💡 What is Virtual DOM?

The Virtual DOM is a virtual tree structure in memory that replicates the browser's real DOM. In other words, instead of directly manipulating the browser DOM,

it virtually "computes (diffs)" the changes and reflects only the minimum updates.

// Example of React internal concepts
const vdom1 = <div><p>Hello</p></div>
const vdom2 = <div><p>Hello, world!</p></div>
 
// After calculating the differences, only update the actual DOM where necessary.
updateDOM(diff(vdom1, vdom2))

The Virtual DOM is not a "fast DOM,"
but rather a "strategy to minimize DOM changes and increase efficiency."

--

🧩 What is the Real DOM?

The Real DOM is the Document Object Model that the browser actually renders.

const el = document.createElement('div')
el.textContent = 'Hello DOM'
document.body.appendChild(el)

This structure is simple, but the problem is that the browser must recalculate every time you change it.

  1. Recalculate Style

  2. Layout / Reflow

  3. Paint / Composite

In other words, the more frequently you change the DOM, the more performance degrades.

This is where the Virtual DOM comes in.


⚙️ Try this yourself (accurate comparison version)

🧪 1) Real DOM method — initial rendering

<div id="root"></div>
<script>
    const root = document.getElementById('root')
    const start = performance.now()
 
    for (let i = 0; i < 10000; i++) {
        const el = document.createElement('div')
        el.textContent = i
        root.appendChild(el)
    }
 
    const end = performance.now()
    console.log('Real DOM Render Time:', end - start, 'ms')
</script>

💥 When you run it, the screen freezes for a moment, but it finishes faster than you might expect.
In reality, it's likely to be faster than React

(typically around 200-500ms)

Because Real DOM simply iterates over appendChild.


🧪 2) Virtual DOM (React) — Initial rendering

<div id="root"></div>
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
 
<script>
    const { createElement } = React
 
    const App = () => {
        const items = Array.from({ length: 10000 }, (_, i) => createElement('div', { key: i }, i))
        return createElement('div', null, items)
    }
 
    const start = performance.now()
    ReactDOM.render(createElement(App), document.getElementById('root'))
    const end = performance.now()
    console.log('Virtual DOM Render Time:', end - start, 'ms')
</script>
 

🧯 The result is surprisingly slower.

This is because React internally performs the following steps:

  1. Create a Virtual DOM tree (structure in memory)
  2. Prepare for diff calculation (initialize the Fiber structure)
  3. Apply the Real DOM all at once (Commit phase)

In other words, the Virtual DOM suffers in the first render (approximately 400-900ms).


🔁 Real Comparison: Repeated Updates

The real power of the Virtual DOM comes into play when the state is constantly changing.

Let's update just a few of the 10,000 elements.

<div id="root"></div>
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script>
    const { createElement, useState } = React
 
    const App = () => {
        const [data, setData] = useState(Array.from({ length: 10000 }, (_, i) => i))
        const updateRandom = () => {
            const copy = [...data]
            const random = Math.floor(Math.random() * 10000)
            copy[random] = Math.random()
            setData(copy)
        }
        return createElement('div', null, createElement('button', { onClick: updateRandom }, 'Update Random Item'), ...data.map((n, i) => createElement('div', { key: i }, n)))
    }
 
    ReactDOM.render(createElement(App), document.getElementById('root'))
</script>

Now, keep clicking the button! 👇

React computes a diff and updates only the single element that changed.

The browser barely flickers.

If we were to implement the same thing with Real DOM,

we'd have to redraw the entire page with root.innerHTML = ... every time, which would be much slower.

✅ Virtual DOM is "slow once, fast afterwards."

--

📊 Summary: Which is faster?

Situation Real DOM Virtual DOM
Initial Render Fast (Simple Append) Slow (Tree Creation + Diff Structure)
Partial Update Slow (Full Reflow) Fast (Minimum Changes After Diff)
Memory Usage Low High (VDOM Tree Storage)
Suitable For Static Pages, Simple UI SPA / App-Type UI with Frequent State Changes

🧠 How to Use It in Practice?

Situation Recommended Method Reason
General Web App / SPA Virtual DOM (React, Vue) Automatic Change Tracking, Easy Maintenance
Data Visualization / Canvas Real DOM / Direct Control Prevent Virtual DOM Overhead
Large Lists Virtual DOM + Virtualized List Rendering Only the Scrolling Area
Simple Landing Page Real DOM Faster initial load

In other words, the misconception that "Virtual DOM is always faster" is true.

The key is "which strategy is right in which situation?"


💬 Conclusion

  • Virtual DOM isn't a "technology that speeds up rendering,"

but rather a "technology that makes repeated updates efficient."

  • While the initial render may be slower,

it's much more efficient in the long run for UIs that change frequently.

Virtual DOM = Starts slow, but stays fast.

Real DOM = Starts fast, but becomes more demanding over time.


📚 References


#VirtualDOM #RealDOM #React #RenderingPerformance #Front-EndPerformance #BrowserRendering #Reflow #SPA #WebPerformance #JavaScript

Virtual DOM vs. Real DOM — A Hands-On Rendering Performance Comparison · Simoong Blog